Подтвердить что ты не робот

Как отправлять/помещать данные json в ListSerializer

Я читаю о настройке нескольких обновлений здесь, и я не понял, в каком случае вызывается пользовательский метод обновления ListSerializer, Я хотел бы обновить сразу несколько объектов, я не беспокоюсь о множественном создании или удалении на данный момент.

Из примера в документах:

# serializers.py
class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # custom update logic
        ...

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer

И мой ViewSet

# api.py
class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

И моя настройка url с помощью DefaultRouter

# urls.py
router = routers.DefaultRouter()
router.register(r'Book', BookViewSet)

urlpatterns = patterns('',                       
    url(r'^api/', include(router.urls)),
    ...

Итак, я настроил его с помощью DefaultRouter, чтобы /api/Book/ использовал BookSerializer.

Является ли общая идея, что если я POST/PUT/PATCH массив объектов JSON для /api/Book/, то сериализатор должен переключиться на BookListSerializer?

Я пробовал список данных POST/PUT/PATCH JSON для этого /api/Book/, который выглядит так:

[ {id:1,title:thing1}, {id:2, title:thing2} ]

но он по-прежнему обрабатывает данные, используя BookSerializer вместо BookListSerializer. Если я отправлю через POST, я получаю Invalid data. Expected a dictionary, but got list. и если я отправлю через PATCH или PUT, я получаю ошибку Method 'PATCH' not allowed.

Вопрос: Нужно ли настраивать allowed_methods DefaultRouter или BookViewSet, чтобы разрешать POST/PATCH/PUT списков? Являются ли общие представления не настроены для работы с ListSerializer?

Я знаю, что я мог бы написать свой собственный десериализатор списка для этого, но я стараюсь быть в курсе новых функций в DRF 3, и похоже, что это должно работать, но я просто пропускаю какое-то соглашение или какой-то вариант.

4b9b3361

Ответ 1

Структура Django REST по умолчанию предполагает, что вы не имеете дело с массовым созданием, обновлением или удалением данных. Это связано с тем, что 99% людей не занимаются созданием объемных данных, а DRF оставляет другие 1% в сторонних библиотеках.

В Django REST framework 2.x и 3.x для него существует сторонний пакет .

Теперь вы пытаетесь сделать массовое создание, но вы получаете сообщение об ошибке, которое говорит

Недействительные данные. Ожидаемый словарь, но получил список

Это потому, что вы отправляете список объектов для создания вместо того, чтобы просто отправлять их. Вы можете обойти это несколькими способами, но проще всего просто переопределить get_serializer в вашем представлении до добавить many=True флаг в сериализатор, когда это список.

def get_serializer(self, *args, **kwargs):
    if "data" in kwargs:
        data = kwargs["data"]

        if isinstance(data, list):
            kwargs["many"] = True

    return super(MyViewSet, self).get_serializer(*args, **kwargs)

Это позволит инфраструктуре Django REST знать, как автоматически использовать ListSerializer при создании объектов навалом. Теперь для других операций, таких как обновление и удаление, вам придется переопределить маршруты по умолчанию. Я предполагаю, что вы используете маршруты предоставленные основной картой Django REST, но вы можете использовать любые имена методов, которые вы хотите.

Вам нужно будет добавить методы для массовых PUT и PATCH в представление.

from rest_framework.response import Response

def bulk_update(self, request, *args, **kwargs):
    partial = kwargs.pop("partial", False)

    queryset = self.filter_queryset(self.get_queryset))

    serializer = self.get_serializer(instance=queryset, data=request.data, many=True)
    serializer.is_valid(raise_exception=True)

    self.perform_update(serializer)

    return Response(serializer.data)

def partial_bulk_update(self, *args, **kwargs):
    kargs["partial"] = True
    return super(MyView, self).bulk_update(*args, **kwargs)

Это не будет работать из коробки, поскольку Django REST framework по умолчанию не поддерживает массовые обновления. Это означает, что вы также должны выполнять собственные массовые обновления. Текущий код будет обрабатывать массовые обновления, как если бы вы пытались обновить весь список, как ранее работал старый пакет обновления.

Пока вы не запрашивали массовое удаление, это не было бы особенно сложно сделать.

def bulk_delete(self, request, *args, **kwargs):
    queryset = self.filter_queryset(self.get_queryset())
    self.perform_delete(queryset)
    return Response(status=204)

Это оказывает такое же влияние на удаление всех объектов, как и старый массовый плагин.

Ни один из этих кодов не был протестирован. Если это не сработает, рассмотрите его как подробный пример.