Попытка массового обновления списка приоритетов - DRF

Я пытаюсь массово обновить весь свой список приоритетов. Вот модель:

class OrderPriority(models.Model):
    order = models.OneToOneField(Order, related_name='priority_order', on_delete=models.CASCADE)
    priority = models.BigIntegerField(unique=True)

Вот мой Bulk Update Serializer и List Serializer Class:

class BulkPriorityUpdateListSerializer(serializers.ListSerializer):

    def update(self, instances, validated_data):

        instance_hash = {index: instance for index, instance in enumerate(instances)}

        result = [
            self.child.update(instance_hash[index], attrs)
            for index, attrs in enumerate(validated_data)
        ]

        writable_fields = [
            x
            for x in self.child.Meta.fields
            if x not in self.child.Meta.read_only_fields
        ]
        
        try:
            self.child.Meta.model.objects.bulk_update(result, writable_fields)
        except IntegrityError as e:
            raise ValidationError(e)

        return result
    
    def to_representation(self, instances):

        rep_list = []
        for instance in instances:
            rep_list.append(
                dict(
                    id=instance.id,
                    order=instance.order.id,
                    priority=instance.priority,
                )
            )

        return rep_list

class BulkOrderPrioritySerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderPriority
        fields = ("id", "order", "priority")
        read_only_fields = ("id",)
        list_serializer_class = BulkPriorityUpdateListSerializer

Вот мое представление вместе с пользовательским представлением массового обновления:

class CustomBulkUpdateAPIView(generics.UpdateAPIView):
    
    def update(self, request, *args, **kwargs):
        def validate_ids(data, field="id", unique=True):

            if isinstance(data, list):
                id_list = [int(x[field]) for x in data]

                if unique and len(id_list) != len(set(id_list)):
                    raise ValidationError("Multiple updates to a single {} found".format(field))
                return id_list
            
            return [data]

        ids = validate_ids(request.data)

        instances = self.get_queryset(ids=ids)
        serializer = self.get_serializer(
            instances, data=request.data, partial=False, many=True
        )
        serializer.is_valid(raise_exception=True)

        self.perform_update(serializer)

        return Response(serializer.data)

class OrderPriorityUpdateAPIView(CustomBulkUpdateAPIView):
    serializer_class = BulkOrderPrioritySerializer
    
    def get_queryset(self, ids=None):
        return OrderPriority.objects.filter(
            id__in=ids,
        )

Затем я отправляю массовый запрос PUT с телом:

[
    {
        "id": 1,
        "priority": 1,
        "order": 109
    },
    {
        "id": 2,
        "priority": 2,
        "order": 110
    },
    {
        "id": 3,
        "priority": 3,
        "order": 111
    },
    {
        "id": 4,
        "priority": 4,
        "order": 112
    },
    {
        "id": 5,
        "priority": 5,
        "order": 113
    }
]

Затем я получаю ошибку:

Я следовал руководству по массовому обновлению из здесь, и я также использовал его раньше без проблем. Не уверен, что именно вызывает проблему. Похоже, проблема возникает, когда я проверяю .is_valid. Может быть, я неправильно передаю данные? Может быть, дело в том, что приоритет - это уникальное поле? Любая помощь будет принята с благодарностью.

Думаю, это относится к https://github.com/miki725/django-rest-framework-bulk/issues/68

По сути, я думаю, что проблема заключается в том, что дочерний сериализатор пытается выполнить проверку на весь QuerySet, проверяя наличие pk.

Ваш QuerySet не содержит pk; однако каждый экземпляр QuerySet содержит его.

Решением является переписывание метода to_internal_value() в классе ListSerializer для передачи каждого экземпляра по одному в child.serializer и запуск проверки:

self.child.instance = self.instance.get(id=item['id']) if self.instance else None
self.child.initial_data = item
validated = self.child.run_validation(item)

Надеюсь, это поможет

Вернуться на верх