在 Django REST 框架的 API 根中包含 list_route 方法

Include list_route methods in Django REST framework's API root

我正在使用 Django REST 框架,并且我有一个带有额外列表路由方法的视图集。我如何才能将该方法的 URL 包含在 API 根页面中?

这是我的视图集的简化版本:

class BookViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = (permissions.IsAuthenticated, )

    @list_route(methods=['get'])
    def featured(self, request):
        queryset = self.filter_queryset(self.get_queryset()).filter(featured=True)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

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

我注册了urls.py中设置的视图:

router = DefaultRouter()
router.register('books', BookViewSet)
urlpatterns = patterns(
    url(r'^api/', include(router.urls), name='api_home'),
    #...
    )

books/featured 的 URL 路由正确,但是当我转到 http://localhost:8000/api 时,我只看到这个:

HTTP 200 OK
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS

{
    "books": "http://localhost:8000/api/books/"
}

如何为这样的内容添加条目?

"book-featured-list": "http://localhost:8000/api/books/featured"

你能试试吗,把这个放在你的 url 模式下面。 您的 url 将是这样的:

http://localhost:8000/api/books/

from rest_framework.urlpatterns import format_suffix_patterns

urlpatterns = format_suffix_patterns(urlpatterns)

您可以尝试从负责 api 根视图的 DefaultRouter 继承并重新定义 get_api_root_view 方法。

class MyRouter(routers.DefaultRouter):
    def get_api_root_view(self):
        """
        Return a view to use as the API root.
        """
        api_root_dict = OrderedDict()
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry:
            api_root_dict[prefix] = list_name.format(basename=basename)

        class APIRoot(views.APIView):
            _ignore_model_permissions = True

            def get(self, request, *args, **kwargs):
                ret = OrderedDict()
                namespace = request.resolver_match.namespace
                for key, url_name in api_root_dict.items():
                    if namespace:
                        url_name = namespace + ':' + url_name
                    try:
                        ret[key] = reverse(
                            url_name,
                            args=args,
                            kwargs=kwargs,
                            request=request,
                            format=kwargs.get('format', None)
                        )
                    except NoReverseMatch:
                        # Don't bail out if eg. no list routes exist, only detail routes.
                        continue

                ret['book-featured-list'] = '%s%s' % (ret['books'], 'featured/')

                return Response(ret)

        return APIRoot.as_view()

P.S。抱歉,在我发布答案之前没有看到您的评论

您可以安装 django-rest-swagger 包,只需按照这里:https://github.com/marcgibbons/django-rest-swagger

它比 DRF 的 api 列表页面更强大。它会为你的模块列出所有剩余的 apis(包括 list_route/detail_route apis),你也可以在页面上做一些 api 测试(CRUD)。

我根据 likeon 的回答使用这个解决方案:

class MyRouter(routers.DefaultRouter):
    def get_api_root_view(self, api_urls=None):
        api_root_dict = OrderedDict()
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry:
            api_root_dict[prefix] = list_name.format(basename=basename)

        api_root_dict['books/featured'] = 'book-featured'

        return self.APIRootView.as_view(api_root_dict=api_root_dict)