Django Rest Framework: POST для Viewset с параметром URL - PullRequest
1 голос
/ 23 февраля 2020

Как правило, в DRF Viewset вы можете сделать что-то вроде этого:

class FooViewSet(viewsets.ViewSet):
    """
    Foo-related viewsets.
    """
    permission_classes = [IsAuthenticated,]

    def list(self, request):
        """
        A list of foo objects.
        """
        context = {'request': self.request}
        queryset = Foo.objects.all()
        serializer = FooSerializer(queryset, many=True, context=context)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        """
        Get one publicly available Foo item.
        """
        context = {'request': self.request}
        queryset = Foo.objects.all()
        store_object = get_object_or_404(queryset, pk=pk)
        serializer = FooSerializer(store_object, context=context)
        return Response(serializer.data)

Это отлично работает и соответственно соотносится с:

GET /foo и GET /foo/<pk>. Тем не менее, последняя конечная точка мне нужна POST /foo/<pk>. Проблема здесь в том, что предоставление метода create для представлений, как правило, будет направлено на POST /foo. Есть ли что-нибудь аккуратное и элегантное, что я могу сделать из самого ViewSet? Или единственная опция в основном направляет POST /foo/<pk> к определенному c одноразовому представлению?

1 Ответ

0 голосов
/ 24 февраля 2020

Итак, я бы сказал в вашем urls.py для конечных точек REST, которые вам нужны:

urlpatterns = [
    path(
        '/foo',
        viewsets.FooViewSet.as_view({'post': 'create'}),
        name='Create Foo',
    ),
    path(
        '/foo',
        viewsets.FooViewSet.as_view({'get': 'list'}),
        name='List Foo',
    )
    path(
        '/foo/<pk>',
        viewsets.FooViewSet.as_view({'get': 'retrieve'}),
        name='Retrieve Foo',
    )
]

Обычно принято patch (частичное обновление) или put (обновление) до /foo/<pk> конечная точка.

Поэтому отправьте на базовую /foo конечную точку с десериализованным представлением JSON объекта, который вы хотите создать (минус pk, позвольте БД создать pk на лету).

Если вы хотите обновить foo, просто добавьте:

urlpatterns = [
    ...
    path(
        '/foo/<pk>',
        viewsets.FooViewSet.as_view({'put': 'update'}),
        name='Update Foo',
    ),
    path(
        '/foo/<pk>',
        viewsets.FooViewSet.as_view({'patch': 'partial_update'}),
        name='Partially Update Foo',
    )
]

Это будет соответствовать вашему FooViewSet как следующему, как наиболее базовый c пример as:

class FooViewSet(viewsets.ViewSet):

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

Замена каждой из необходимых конечных точек требуемым кодом. Уход в проход также запретит этот метод, что удобно, например, если вы хотите sh отключить действие уничтожения в вашем API.

Приложение : стоит добавить вас может также сделать следующее:

urlpatterns = [
    path(
        '/foo',
        viewsets.FooViewSet.as_view({'post': 'custom_post_action'}),
        name='Create Foo',
    ),

С соответствующим в вашем FooViewSet():

class FooViewSet(viewsets.ViewSet):
    ...

    @action(methods=['post'], detail=False, permission_classes=[SomePermissionClass], url_path='?', url_name='?')
    def custom_post_action(self, request):
        pass

Если вы будете sh, то я считаю, что это может быть плохой практикой, а не действительно представитель принципов "RESTful", но кто дает CRUD, если это то, что вам нужно?

...