Django Rest Framework:使用 URL 参数 POST 到 Viewset

aro*_*ooo 6 django django-models django-rest-framework

通常,在 DRF 视图集中,您可能会执行以下操作:

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)
Run Code Online (Sandbox Code Playgroud)

这工作得很好,并且分别与:

GET /fooGET /foo/<pk>。但是,我需要的最后一个端点是POST /foo/<pk>. 这里的问题是,create为视图提供方法通常会被路由到POST /foo. 我可以从 ViewSet 本身做一些简洁而优雅的事情吗?POST /foo/<pk>或者基本上是路由到特定的一次性视图的唯一选择?

Mic*_*rts 5

因此,我会在您的urls.pyREST 端点中说您需要:

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',
    )
]
Run Code Online (Sandbox Code Playgroud)

约定仅patch(部分更新)或put(更新)端点/foo/<pk>

因此,使用要创建的对象的 JSON 反序列化表示形式发布到基本/foo端点(减去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',
    )
]
Run Code Online (Sandbox Code Playgroud)

这将对应于您的 FooViewSet,如下所示,最基本的示例如下:

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
Run Code Online (Sandbox Code Playgroud)

将每个所需的端点替换为您想要的代码。保留 pass 也会禁止该方法,例如,如果您希望禁用 API 上的销毁操作,这会很方便。

附录:值得补充的是,您还可以执行以下操作:

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

与您的相应FooViewSet()

class FooViewSet(viewsets.ViewSet):
    ...

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

如果您愿意,我觉得这可能是不好的做法,并且不能真正代表“ RESTful”原则,但是如果您需要的话,谁会提供 CRUD?