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

时间:2017-12-14 09:07:18

标签: python django django-serializer

我需要在一个请求中更新categoriesArticle

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]]
}

3 个答案:

答案 0 :(得分:1)

以下是您请求的CreateMixins或UpdateMixins示例。

=======================查看======================= =========

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

    def get_queryset(self):
        return []

    def get_serializer_class(self):
        return serializers.OrderSerializer

======================= Serializer ======================= ==

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

在更新视图中,功能名称将更改为更新,您可以找到更多文档 http://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin

答案 1 :(得分:1)

我发现K. Moe对以下问题的回答:Django Rest Framework POST Update if existing or create更容易理解和实施。您只需要在序列化器中添加一个create方法,并在视图中使用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)

答案 2 :(得分:0)

@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)

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