Есть ли эквивалент get_model для сериализаторов? - PullRequest
0 голосов
/ 11 июля 2019

Я читал документы по сериализаторам и Google (много), но не нашел точного ответа, который я ищу.

Я пытаюсь написать общий процесс (класс) «архив» для обработки изменения поля состояния на «заархивировано» для любого экземпляра модели на основе того, что передано в URL.

Например:

example.com/archive/clients.client/123

Это изменило бы статус на «заархивированный» для идентификатора 123 модели клиента.

Вот мой URLconf:

path('archive/<model>/<int:pk>/', Archive.as_view()),

А вот мой класс просмотра. Сначала я получил это для конкретной модели, поэтому скопировал этот код и пытаюсь адаптировать его, чтобы он был более универсальным. Кроме того, я знаю, что это требует большей пуленепробиваемости, но я пытаюсь показать простейшую версию моего кода.

class Archive(RetrieveAPIView):

    def retrieve(self, request, model=None, pk=None, *args, **kwargs):
        app, model_name = model.split('.')

        get_model = apps.get_model
        model = get_model(app, model_name)
        self.queryset = model.objects.all()

        instance = self.get_object(pk=pk)

        if instance.status == 'archived':
            return APIMessage('That item has already been archived.', message_code='already_archived')

        setattr(instance, 'status', 'archived')
        instance.save()

        serializer = self.get_serializer(instance)
        return Response(serializer.data)

Когда я пытаюсь запустить все как есть, я получаю:

'Archive' should either include a `serializer_class` attribute, or override the `get_serializer_class()` method.

И это было в значительной степени то, что я ожидал, но у меня нет ничего, что я мог бы на самом деле установить serializer_class с самого начала, и если я установлю его на None, я получу ту же ошибку. Конечно, я уже знал о get_serializer_class, но здесь мне понадобится что-то вроде get_model, за исключением того, что он будет возвращать класс сериализатора на основе модели, которую я определил по URL.

1 Ответ

2 голосов
/ 11 июля 2019

Поскольку вы обновляете свой ресурс, вы должны использовать представление, поддерживающее запросы PUT / PATCH, которые предназначены именно для обновления свойств по проекту (в HTTP).

RetrieveAPIView is:

Используется для конечных точек только для чтения для представления отдельного экземпляра модели

В вашем конкретном случае вы должны использовать наиболее общий APIView от DRF, поскольку он не требует определения serializer_class и других свойств, которые вы не будете использовать.

from rest_framework.views import APIView


class Archive(APIView):
    def put(self, request, model=None, pk=None, *args, **kwargs):
        app, model_name = model.split('.')

        get_model = apps.get_model
        model = get_model(app, model_name)
        self.queryset = model.objects.all()

        instance = self.get_object(pk=pk)

        if instance.status == 'archived':
            return APIMessage('That item has already been archived.', message_code='already_archived')

        setattr(instance, 'status', 'archived')
        instance.save()

        return Response({'success': True})

    def patch(self, request, *args, **kwargs):
        return self.put(request, *args, **kwargs)

Это должно сработать.Я также сопоставил метод PATCH для выполнения логики PUT, что означает, что вы можете использовать оба этих метода HTTP для обновления экземпляра вашей модели.

Теперь ваше представление настолько универсально, насколько это возможно, с помощью APIView.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...