使用Django Rest Framework的可浏览API和APIViews?

Dav*_*ver 37 django-rest-framework

如果我有一个看法:

class MyAPIView(APIView):
    def get(self, request, name=None):
        return {"hello": name or "world"}
Run Code Online (Sandbox Code Playgroud)

如何将生成的文档中包含的内容包含在内?具体来说,如何将其包含在API Root中,以便在我访问" http://example.com/api/ "时显示?

文档包含带有描述的APIView 的示例,但没有描述实际将其包含在API浏览器中的过程.

imy*_*suf 29

要混合路由器和APIView类或方法,以便API根在APIRoot视图中以最少的代码视图显示,我编写了一个自定义路由器,它扩展了DefaultRouter并覆盖了get_urls和get_api_root_view; 它看起来如下:

from rest_framework import routers, views, reverse, response

class HybridRouter(routers.DefaultRouter):
    def __init__(self, *args, **kwargs):
        super(HybridRouter, self).__init__(*args, **kwargs)
        self._api_view_urls = {}

    def add_api_view(self, name, url):
        self._api_view_urls[name] = url

    def remove_api_view(self, name):
        del self._api_view_urls[name]

    @property
    def api_view_urls(self):
        ret = {}
        ret.update(self._api_view_urls)
        return ret

    def get_urls(self):
        urls = super(HybridRouter, self).get_urls()
        for api_view_key in self._api_view_urls.keys():
            urls.append(self._api_view_urls[api_view_key])
        return urls

    def get_api_root_view(self):
        # Copy the following block from Default Router
        api_root_dict = {}
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry:
            api_root_dict[prefix] = list_name.format(basename=basename)
        api_view_urls = self._api_view_urls

        class APIRoot(views.APIView):
            _ignore_model_permissions = True

            def get(self, request, format=None):
                ret = {}
                for key, url_name in api_root_dict.items():
                    ret[key] = reverse.reverse(url_name, request=request, format=format)
                # In addition to what had been added, now add the APIView urls
                for api_view_key in api_view_urls.keys():
                    ret[api_view_key] = reverse.reverse(api_view_urls[api_view_key].name, request=request, format=format)
                return response.Response(ret)

        return APIRoot.as_view()
Run Code Online (Sandbox Code Playgroud)

然后我用它作为 -

router = routers.HybridRouter()
router.register(r'abc', views.ABCViewSet)
router.add_api_view("api-view", url(r'^aview/$', views.AView.as_view(), name='aview-name'))
urlpatterns = patterns('',
    url(r'^api/', include(router.urls)),
Run Code Online (Sandbox Code Playgroud)

  • 我想注意,自从这篇文章以来,DefaultRouter的源代码已经发生了变化,所以你从DefualtRouter逐字复制的那段代码现在已经过时了.我尝试了这段代码,它失败了,例外:`/ NoiverseMatch at/api /`:`反向'cathegory-list',参数'()'和关键字参数'{}'找不到.0模式试过:[]` (2认同)

Tom*_*tie 17

生成的文档?

嗨大卫,第一次了,我也不会描述可浏览的API为"生成的文档".

如果您需要静态文档,最好放在像django-rest-swagger这样的第三方工具上.

可浏览的API确实意味着您构建的API将是自描述的,但它与传统的静态文档工具略有不同.可浏览的API确保您在API中创建的所有端点都能够使用机器可读(即JSON)和人类可读(即HTML)表示进行响应.它还确保您可以通过浏览器直接完全交互 - 您通常使用程序化客户端进行交互的任何URL也能够通过浏览器友好的视图响应API.

我怎样才能得到它.

只需在视图中添加文档字符串,它就会包含在您浏览到该视图的任何URL的可浏览API表示中.

默认情况下,您可以使用markdown表示法在说明中包含HTML标记,但您也可以自定义该行为,例如,如果您更愿意使用rst.

具体来说,我如何将它包含在API Root中.

您只需要将URL显式添加到由您连接的任何视图返回的响应中/api/.例如...

from rest_framework import renderers
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.reverse import reverse


class APIRoot(APIView):
    def get(self, request):
        # Assuming we have views named 'foo-view' and 'bar-view'
        # in our project's URLconf.
        return Response({
            'foo': reverse('foo-view', request=request),
            'bar': reverse('bar-view', request=request)
        })
Run Code Online (Sandbox Code Playgroud)

  • 如果您还定义了通过路由器注册的ViewSets,是否可以在API根目录中包含基于类的视图? (24认同)

nai*_*gun 5

我针对我的用例优化了 HybridRouter 并删除了一些代码。一探究竟:

class HybridRouter(routers.DefaultRouter):
    def __init__(self, *args, **kwargs):
        super(HybridRouter, self).__init__(*args, **kwargs)
        self.view_urls = []

    def add_url(self, view):
        self.view_urls.append(view)

    def get_urls(self):
        return super(HybridRouter, self).get_urls() + self.view_urls

    def get_api_root_view(self):
        original_view = super(HybridRouter, self).get_api_root_view()

        def view(request, *args, **kwargs):
            resp = original_view(request, *args, **kwargs)
            namespace = request.resolver_match.namespace
            for view_url in self.view_urls:
                name = view_url.name
                url_name = name
                if namespace:
                    url_name = namespace + ':' + url_name
                resp.data[name] = reverse(url_name,
                                          args=args,
                                          kwargs=kwargs,
                                          request=request,
                                          format=kwargs.get('format', None))
            return resp
        return view
Run Code Online (Sandbox Code Playgroud)

及用法:

router = routers.HybridRouter(trailing_slash=False)
router.add_url(url(r'^me', v1.me.view, name='me'))
router.add_url(url(r'^status', v1.status.view, name='status'))

urlpatterns = router.urls
Run Code Online (Sandbox Code Playgroud)

或者:

router = routers.HybridRouter(trailing_slash=False)
router.view_urls = [
    url(r'^me', v1.me.view, name='me'),
    url(r'^status', v1.status.view, name='status'),
]

urlpatterns = router.urls
Run Code Online (Sandbox Code Playgroud)