如何在 Django 中一次更新多条记录(批量更新)API

How to update multiple records at once (bulk update) in django API

我需要在一个请求中更新 categories 多个 Article

ArticleViewSet我有:

def get_serializer_class(self):
    if self.action in ['partial_update', 'update']:
        return ArticlePostSerializer
    return ArticleSerializer

所以ArticlePostSerializer需要更改。

这是我的序列化程序代码:

class ArticleShortCategorySerializer(serializers.ModelSerializer):

    class Meta:
        model = Category
        fields = 'id', 'name'


class ArticleSerializer(serializers.ModelSerializer):
    categories = serializers.SerializerMethodField()

    def get_categories(self, obj):
        return ArticleShortCategorySerializer(obj.categories, many=True).data

    class Meta:
        model = Article
        read_only_fields = 'id'
        fields = ('categories', 'text') + read_only_fields


class ArticlePostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = 'id', 'categories', 'text'

我尝试添加:

class ArticlePostListSerializer(serializers.ListSerializer):

class Meta:
    list_serializer_class = ArticlePostListSerializer

但它不起作用。 如何更改此代码以进行多次更新。 我的 json 请求

{
    [id: 90, categories: [10,12,14]],
    [id: 93, categories: [10,12,14]],
    [id: 95, categories: [10,12,14]]
}

这是您请求的 CreateMixins 或 UpdateMixins 的示例。

=======================视图===================== ===========

class OrderCreate(mixins.CreateModelMixin,viewsets.GenericViewSet):
    pagination_class = None

    def get_queryset(self):
        return []

    def get_serializer_class(self):
        return serializers.OrderSerializer

=======================序列化器===================== ========

class OrderDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = crm_models.OrderDetail
        fields = (
                'product',
                'quantity',
                'rate_per_unit',
                'order_quantity'
                )

class OrderSerializer(serializers.ModelSerializer):
    order_details = OrderDetailSerializer(many = True)
    class Meta:
        model = crm_models.OrderMaster
        fields = (
                'order',
                'invoice_number',
                'client',
                'beat_check',
                'target_customer',
                'order_editor_client_employee',
                'order_marked',
                'order_saved',
                'edit_marked',
                'edit_saved',
                'adhoc',
                'order_details'
                )

    def create(self, validated_data,*args,**kwargs):
        ordersdetails_data = validated_data.pop('order_details')
        user = None
        request = self.context.get("request")
        if request and hasattr(request, "user"):
            user = request.user
            validated_data['client'] = user.client
            validated_data['order_editor_client_employee'] = user
            validated_data['adhoc'] = validated_data['adhoc'] if 'adhoc' in validated_data else False

        orderObj = super(OrderSerializer, self).create(validated_data,*args,**kwargs)
        orderdetails = []
        for details in ordersdetails_data:
            orderdetails.append(crm_models.OrderDetail(
                product= details['product'],
                quantity = details['quantity'],
                rate_per_unit = details['rate_per_unit'],
                order_quantity = details['order_quantity'],
                order = orderObj
            ))
        crm_models.OrderDetail.objects.bulk_create(orderdetails)
        return orderObj

Update 视图函数名称将更改为 update,您可以找到更多文档 http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin

我发现 K. Moe 对这个问题的回答: 更容易理解和实施。只需要在serializer中添加create方法,在view中使用mixins.CreateModelMixin、generics.GenericAPIView即可。然后你可以使用 POST 请求,而不是 PUT/PATCH。它允许创建和更新存储在数据库中的数据。我的视图代码:

class ZipCodeList(mixins.CreateModelMixin, generics.GenericAPIView):    
    def post(self, request, format=None):
        is_many = isinstance(request.data, list)

        if is_many:
            serializer = ZipCodeSerializer(data=request.data, many=True)
            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)

        else:
            serializer = ZipCodeSerializer(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)

@Greg Holst,为什么会有这么多重复?为什么不呢:

class ZipCodeList(mixins.CreateModelMixin, generics.GenericAPIView):
    def post(self, request, format=None):
        serializer = ZipCodeSerializer(data=request.data, many=isinstance(request.data, list))
        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)

无论如何,这只对我创建新对象有效,对一次性创建或更新无效(它一直告诉我这些对象已经存在),所以这就是我所做的:

class ContributorSyncListAPIView(ListAPIView):
    permission_classes = (isSuperUserPermission,)
    allowed_methods = ("GET", "PUT")
    lookup_field = "airtable_id"
    serializer_class = ContributorSyncSerializer  # Doesn't get used in Put, just in Get.
    model = Contributor

    def get_queryset(self):
        return self.model.objects.all()

    def put(self, request, format=None):
        objects = list(request.data)
        # objects is a list of OrderedDicts
        try:
            for o in objects:
                try:
                    instance = self.model.objects.get(
                        **{self.lookup_field: o.get(self.lookup_field)}
                    )
                    for key, value in o.items():
                        setattr(instance, key, value)
                except self.model.DoesNotExist:
                    instance = self.model(**o)
                instance.save()
            return Response(objects, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)

请注意,我上面的代码在验证方面非常简单,因为它是用于超级用户将模型从一个环境同步到另一个环境的过程,不同的环境具有相同的代码库;因此假设数据在输入第一个环境时已经过验证。对于任何其他目的,您需要验证更多。但这是我必须做的,以逐个对象地处理可能需要创建或更新的对象列表。