【问题标题】:Django Rest Framework: POST to Viewset with URL parameterDjango Rest Framework:使用 URL 参数 POST 到 Viewset
【发布时间】:2020-06-07 02:56:17
【问题描述】:

通常,在 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)

这很好用,并且分别对应于:

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

【问题讨论】:

  • 我的回答是否有助于解决您的问题?

标签: django django-models django-rest-framework


【解决方案1】:

所以,我会在您的 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/&lt;pk&gt; 端点。

因此,使用您要创建的对象的 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',
    )
]

这将对应于您的 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

用您想要的代码替换每个需要的端点。保留 pass 也将禁止该方法,例如,如果您希望禁用 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

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

【讨论】:

  • 这很有趣。所以我在这里要做的不是创建一个对象,而是将另一个类型的对象添加到用户的列表中。例如,我们有/notes,我想将其添加到POST /users/notes/&lt;noteiD&gt; 的用户列表中。这不是一个好方法吗?
  • 虽然用户和笔记之间有一些联系,但我可能会组织它更像/users/&lt;user_pk&gt;/notes 以返回给定User 的所有笔记......所以它有点分层结构。 .那么您可以将pkUser 传递给该端点...您是否希望我在我的答案中添加一个潜在的如何做到这一点?
  • 所以在这种情况下,这些笔记都是通用对象,不一定是用户创建的。假设我想将notes/&lt;note_id&gt; 的通用注释(由其他人制作)添加到当前用户的注释列表中。我将如何构建这条路线?
  • Hmmmm,所以我将拥有笔记的所有权关系......这样用户 A 可以创建它们。所以NoteUser 之间的ForeignKey 关系称为owner。然后......可能,NoteUser 之间的 ManyToMany 关系称为 somwething,如 for......
  • 然后我会构建 API,这样您就可以拥有一个仅用于 users/&lt;user_pk&gt;/notes/&lt;note_pk&gt; 的端点...但这在设计上并不是真正的 RESTful,因为您有两个 pk links...您将需要创建相当自定义的端点...我将使用/users/&lt;user_pk&gt; 运行,它将作为字段之一的注释ID序列化列表,然后您可以逐个注释地为用户提供权限然后查看它们。所以自定义permission 类将需要UserCanViewNote,这样如果您传入 pk,当前登录的用户可以查看该注释...否则 404 状态。
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 2014-05-29
  • 2014-07-01
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 2020-05-06
  • 2020-08-26
相关资源
最近更新 更多