【问题标题】:Add custom route to viewsets.ModelViewSet将自定义路由添加到 viewsets.ModelViewSet
【发布时间】:2014-02-02 09:24:52
【问题描述】:

在文档中有自定义 url 的方法示例: http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers

class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @link(renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

此示例添加以下路由:

url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),

可以不加pk参数的url,像这样吗?

r'^snippets/highlight/$'

【问题讨论】:

  • 只需创建您自己的自定义 api 视图..
  • 我只是想推荐drf-extensions,它提供了可以应用于列表端点的@link@action-装饰器(以及扩展路由器)。但是:您在方法中使用get_object。你是否覆盖了它,或者如果url中没有pk,get_object应该如何知道要获取哪个对象?

标签: django django-rest-framework


【解决方案1】:

ViewSets docs 提及使用 action 装饰器:

from rest_framework.decorators import action


class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @action(detail=False, methods=['GET'], name='Get Highlight')
    def highlight(self, request, *args, **kwargs):
        queryset = models.Highlight.objects.all()

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

然后只需更新您的查询集以执行它需要执行的任何操作。

这样做的好处是可以保留您的序列化。

如果您的urls.py 看起来像这样:

from django.contrib import admin
from django.urls import path, include

from rest_framework import routers
from snippets import viewsets

router = routers.DefaultRouter()
router.register('snippets', viewsets.SnippetViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('snippets/', include(router.urls)),
]

那么就可以通过http://localhost:8000/snippets/highlights访问了

要查看POST 的用法或如何更改路由,请参阅docs for routers

【讨论】:

    【解决方案2】:

    由于这个问题仍然出现在第一个 Google 页面上,因此这里是最新的(2020 年 3 月下旬)sn-p(双关语)开始为单个对象处理您的自定义 ModelViewSet 路由:

    from rest_framework.decorators import action
    
    
    class SnippetViewSet(viewsets.ModelViewSet):
        ...
    
        @action(detail=True, methods=['POST'], name='Attach meta items ids')
        def custom_action(self, request, pk=None):
            """Does something on single item."""
            queryset = Snippet.objects.get(pk=pk)
            serializer = self.get_serializer(queryset, many=False)
            return Response(serializer.data)
    

    拥有 DRF 教程中的默认路由器将允许您通过以下方式访问此路由:http://localhost:8000/snippets/&lt;int:pk&gt;/custom_action/

    【讨论】:

    • 我怎样才能做到这一点,但通过 pk ('name') 以外的唯一字段获取对象?
    • 我的意思是通过localhost:8000/snippets/name/<name>获得它
    • @CSZ 只需设置detail=False。不知何故,Django 的人选择使用 detail 表示主键。 ¯_(ツ)_/¯
    【解决方案3】:

    是的,你可以这样做。只需使用 list_route 装饰器将您的方法添加到视图集中即可。

    from rest_framework.decorators import list_route  
    
    class SnippetViewSet(viewsets.ModelViewSet):
        ...
    
        @list_route(renderer_classes=[renderers.StaticHTMLRenderer])
        def highlight(self, request, *args, **kwargs):
            ...
    

    它将添加一个不带pk 参数的网址,例如:

    r'^snippets/highlight/$'
    

    您甚至可以在装饰器中使用 methods 参数指定它支持的方法。

    http://www.django-rest-framework.org/api-guide/routers/#usage

    【讨论】:

    • @list_route() 在最近的版本中被替换为@action(detail=False),请参阅下面@Roman 的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    • 2021-02-06
    • 1970-01-01
    相关资源
    最近更新 更多