在Django Rest框架中更新多对多关系

5 人关注

在我的django应用程序中,我有一个 Orders Packages 之间的多对多关系。一个订单可以有多个包。我想知道关于更新和创建的方法

Models.py

class Package(models.Model):
    prod_name = models.CharField(max_length=255, default=0)
    quantity = models.IntegerField(default=0)
    unit_price = models.IntegerField(default=0)
class Orders(models.Model):
    order_id = models.CharField(max_length=255, default=0)
    package = models.ManyToManyField(Package)
    is_cod = models.BooleanField(default=False)

Serializers.py

class PackageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Package
        fields = "__all__"
class OrderSerializer(serializers.ModelSerializer):
    package = PackageSerializer(many=True)
    class Meta:
        model = Orders
        fields = "__all__"

Views.py

class OrdersCreateAPIView(generics.CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = OrderSerializer
    def post(self, request):
        serializer = OrderSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

这足以处理相关的数据吗?我正在努力理解ManytoMany在Django和DRF中的关系,所以请解释我是否需要改变模型或视图。

我已经更新了我的序列化器以及视图,以便创建像这样的manytomany相关对象。

class OrderSerializer(serializers.ModelSerializer):
    package = PackageSerializer(many=True)
    class Meta:
        model = Orders
        fields = "__all__"
    def create(self, validated_data):
        package_data = validated_data.pop('package')
        pkgs = []
        order = Orders.objects.create(**validated_data)
        for i in package_data:
                p = Package.objects.create(**i)
                pkgs.append(p)
            except:
        order.package.set(pkgs)
        return order

Views.py

class OrdersCreateAPIView(CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = OrderSerializer
    def perform_create(self,serializer):
        serializer.save(owner=self.request.user)

然而,我仍然不清楚重写updateRetrieveUpdateDestroyAPIView方法。另外,上述方法是否是存储M2M相关对象的正确方法?

请帮助解决序列化器的更新部分,我知道我必须在序列化器中传递查询。

5 个评论
JPG
提示:你不需要覆盖 post(....) ,DRF将为您处理 :)
JPG
DRF与FK和M2M关系无缝工作 如果你要发送 PK 并且它是默认行为。在你的情况下,你需要覆盖 create() update() 串行器的方法
@ArakkalAbu 我不需要创建post函数?Post是默认由 serializers 处理的?如果是这样,它不是会创建 object 吗,为什么我必须覆盖创建函数?
JPG
在这里, post() 方法在DB中创建了一个新的对象(理想情况下),它由 generics.CreateAPIView ,而不是通过Serializer。
python
django
django-rest-framework
Rahul Sharma
Rahul Sharma
发布于 2020-05-01
1 个回答
JPG
JPG
发布于 2020-05-07
已采纳
0 人赞同

Working codebase

#serializers.py
class PackageSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    class Meta:
        model = Package
        fields = "__all__"
class OrderSerializer(serializers.ModelSerializer):
    package = PackageSerializer(many=True)
    def get_or_create_packages(self, packages):
        package_ids = []
        for package in packages:
            package_instance, created = Package.objects.get_or_create(pk=package.get('id'), defaults=package)
            package_ids.append(package_instance.pk)
        return package_ids
    def create_or_update_packages(self, packages):
        package_ids = []
        for package in packages:
            package_instance, created = Package.objects.update_or_create(pk=package.get('id'), defaults=package)
            package_ids.append(package_instance.pk)
        return package_ids
    def create(self, validated_data):
        package = validated_data.pop('package', [])
        order = Orders.objects.create(**validated_data)
        order.package.set(self.get_or_create_packages(package))
        return order
    def update(self, instance, validated_data):
        package = validated_data.pop('package', [])
        instance.package.set(self.create_or_update_packages(package))
        fields = ['order_id', 'is_cod']
        for field in fields:
                setattr(instance, field, validated_data[field])
            except KeyError:  # validated_data may not contain all fields during HTTP PATCH
        instance.save()
        return instance
    class Meta:
        model = Orders
        fields = "__all__"
#views.py
class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    queryset = Orders.objects.all()

Register this view with the help of DefaultRouter作为。

from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'order', OrderViewSet, basename='order')
urlpatterns = [
              ] + router.urls

因此,你将得到该表中所描述的基本CRUD端点(见DefaultRouter参考文献)。

Let your order list end-point be /foo-bar/order/

  • HTTP POST to /foo-bar/order/ to create a new instance
  • HTTP PUT or HTTP PATCH to /foo-bar/order/<ORDER_PK>/ to update the content
  • 在这种情况下,如果你希望映射一个现有的 "包",你应该传递id的值。包装Order的关系

    References

  • DRF ModelVieSet
  • Django get_or_create(...)
  • Django create_or_update(...)
  • Django M2M set(...)
  • DRF DefaultRouter
  • urlpatterns = [
        path('foo/order/', OrderViewSet.as_view({'post': 'create'})),  # create new Order instance
        path('foo/order/<int:pk>/', OrderViewSet.as_view({'patch': 'partial_update'})),  # update Order instance