更新 Django Rest Framework 中的多对多关系

Rah*_*rma 1 python django django-rest-framework

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

模型.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)
Run Code Online (Sandbox Code Playgroud)

序列化器.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__"
Run Code Online (Sandbox Code Playgroud)

视图.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)
Run Code Online (Sandbox Code Playgroud)

这足以处理相关数据吗?我试图了解ManytoManyDjango 和 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:
            try:
                p = Package.objects.create(**i)
                pkgs.append(p)
            except:
                pass
        order.package.set(pkgs)
        return order
Run Code Online (Sandbox Code Playgroud)

视图.py

class OrdersCreateAPIView(CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = OrderSerializer

    def perform_create(self,serializer):
        serializer.save(owner=self.request.user)
Run Code Online (Sandbox Code Playgroud)

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

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

JPG*_*JPG 7

工作代码库

#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:
            try:
                setattr(instance, field, validated_data[field])
            except KeyError:  # validated_data may not contain all fields during HTTP PATCH
                pass
        instance.save()
        return instance

    class Meta:
        model = Orders
        fields = "__all__"

#views.py
class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    queryset = Orders.objects.all()
Run Code Online (Sandbox Code Playgroud)

DefaultRouteras的帮助下注册此视图,

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'order', OrderViewSet, basename='order')
urlpatterns = [

              ] + router.urls
Run Code Online (Sandbox Code Playgroud)

因此,您将获得该表中所述的基本 CRUD 端点(请参阅DefaultRouter参考资料)。

让您的订单列表终点为/foo-bar/order/

  1. HTTP POST 以/foo-bar/order/创建新实例
  2. HTTP PUT 或 HTTP PATCH/foo-bar/order/<ORDER_PK>/来更新内容

笔记

在这种情况下,id如果您希望将现有的关系与Order

参考

  1. DRF ModelVieSet
  2. 姜戈 get_or_create(...)
  3. 姜戈 create_or_update(...)
  4. 戈 M2M set(...)
  5. DRF DefaultRouter

更新-1

你可以像这样连接视图

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

]
Run Code Online (Sandbox Code Playgroud)

注意:这仅支持HTTP POSTHTTP PATCH