Django-Rest-Framework 教程: 6. ViewSets 和 Routers

在我们的博客中, 记录了我们在开发过程中所使用的技术和遇到的问题, 希望作为其他开发和设计者的一个学习交流平台.

Django-Rest-Framework 教程: 6. ViewSets 和 Routers


django-rst-framework为我们提供了ViewSet类, ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身. ViewSet类与View类几乎是相同的, 但提供的是read或update, 而不是http动作get或put.

ViewSet类在实例化后, 通过Router类, 最终将URL与ViewSet方法绑定. 接下来我们使用ViewSet代替之前的View.

1. 使用ViewSet

将UserList和UserDetail移除, 并替换为UserViewSet:

    # snippets/views.py
    class UserViewSet(viewsets.ReadOnlyModelViewSet):
        """
        这一viewset提供了`list`和`detail`
        """
        queryset = User.objects.all()
        serializer_class = UserSerializer

我们使用ReadOnlyModelViewSet提供默认的只读权限, queryset和serializer_class设置还是未变.

将SnippetList, SnippetDetail和SnippetHighlight移除, 替换为SnippetViewSet:

    # snippets/views.py
    from rest_framework.decorators import link

    class SnippetViewSet(viewsets.ModelViewSet):
        """
        这一viewset提供了`list`, `create`, `retrieve`, `update` 和 `destroy`

        但我们需要自己设置 `highlight`.
        """
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                              IsOwnerOrReadOnly,)

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

        def pre_save(self, obj):
            obj.owner = self.request.user

我们使用ModelViewSet类实现读写操作API. 我们使用了@link修饰器来创建自定义的highlight动作, 这一修饰器可以用于创建非标准路径. @link修饰器对应的是get request, 如果想对应post request, 可以使用@action修饰器.

2. 明确关联URL

为了更清楚ViewSet内部发生的事情, 我们首先在urls.py中使用明确指明的关联:

    # snippets/urls.py
    from snippets.views import SnippetViewSet, UserViewSet
    from rest_framework import renderers

    snippet_list = SnippetViewSet.as_view({
        'get': 'list',
        'post': 'create'
    })
    snippet_detail = SnippetViewSet.as_view({
        'get': 'retrieve',
        'put': 'update',
        'patch': 'partial_update',
        'delete': 'destroy'
    })
    snippet_highlight = SnippetViewSet.as_view({
        'get': 'highlight'
    }, renderer_classes=[renderers.StaticHTMLRenderer])
    user_list = UserViewSet.as_view({
        'get': 'list'
    })
    user_detail = UserViewSet.as_view({
        'get': 'retrieve'
    })

    urlpatterns = format_suffix_patterns(patterns('snippets.views',
    url(r'^$', 'api_root'),
    url(r'^snippets/$', snippet_list, name='snippet-list'),
    url(r'^snippets/(?P<pk>[0-9]+)/$', snippet_detail, name='snippet-detail'),
    url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),
    url(r'^users/$', user_list, name='user-list'),
    url(r'^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail')
))

3. 使用Router类自动关联URL

Router类可以轻松的帮我们实现URL和ViewSet之间的关联, 我们先注释掉snippets/urls.py中所有内容, 然后重新改写tutorial/urls.py:

    # tutorial/urls.py
    from django.conf.urls import patterns, url, include
    from snippets import views
    from rest_framework.routers import DefaultRouter

    # 黄建router并注册viewset.
    router = DefaultRouter()
    router.register(r'snippets', views.SnippetViewSet)
    router.register(r'users', views.UserViewSet)

    # router会自动生成url
    # 我们只需要额外提供可浏览性登入API
    urlpatterns = patterns('',
        url(r'^', include(router.urls)),
        url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
    )

4. View类和ViewSet类

使用ViewSet类为我们提供了统一的URL地址, 减少了代码的量, 是我们更专注于API本身.

但这不代表一定要使用ViewSet类, ViewSet相对于View更为不明确. 所以在使用中需要特别注意

5. 测试

接下来可以使用之前的方式测试我们的API了.


原文链接: http://weiguda.com/blog/24/