【问题标题】:How to update multiple records at once (bulk update) in django API如何在 django API 中一次更新多条记录(批量更新)
【发布时间】:2018-05-28 07:38:38
【问题描述】:

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

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

【问题讨论】:

  • 使用创建 mixins
  • 在视图中使用 create mixins.CreateModelMixin 并覆盖序列化器中的 Create 方法。或者您可以在 get_queryset 中进行更新工作,但这是个坏主意。
  • @AnupYadav 你能给我一些示例代码吗,怎么做?我是 djnago 的新手。我需要更新记录,我应该使用mixins.CreateModelMixin 还是mixins.UpdateModelMixin
  • 使用其中一个并检查答案中的示例,因为在 cmets 中它无法正确显示。
  • @AnupYadav 所以我不必对ArticleViewSet 进行任何更改?改变序列化器就够了?

标签: python django django-serializer


【解决方案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

======================== 串行器======================= ======

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

【讨论】:

  • 我了解到您可以在您的代码中将OrderDetail 添加到Order。但我需要更新多个Order 记录。
  • 您可以使用我的逻辑来实现这一点,大多数情况下您需要像我一样进行 RAW 工作,基本上您需要获取请求字典,您最好在其中获取客户端通过 JSON 发布的所有数据。您甚至可以在那里添加自定义验证。
  • 我应该用什么 url 发送这个请求 - 和单次更新一样(带 id)?
【解决方案2】:

我发现 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)

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多