Django Rest Framework(第六天)-视图集和路由

一、视图集和路由

REST 框架中的 ViewSet 非常类似 View,它基于一些常用约定,实现了 list, create, retrieve, update, partial_update, destroy 等方法。

ViewSet 在最后的实例化时,才会将 list, create 等方法绑定到 get, post, put, patch, delete 等 REST 操作对应的处理函数(通常由 Router 创建 URL 定义时自动绑定),最后绑定到 model-list, model-create, model-detail 等 URL。

1.1 使用 ViewSet 进行重构

将 UserList 和 UserDetail 视图重构到一个 UserViewSet 中:

# quickstart/views.py

from rest_framework import viewsets

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    这个用户视图集自动提供'list' 和'detail'行为
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

ReadOnlyModelViewSet 实现了只读的操作,如 list, detail 等。

接着将 SnippetList, SnippetDetail SnippetHighlight 重构到一个 SnippetViewSet 中:

# quickstart/views.py

from rest_framework import viewsets
from rest_framework.decorators import detail_route

class SnippetViewSet(viewsets.ModelViewSet):
    """
    这个视图集 自动提供'list' 、'create'、'retrieve'、'update'、'destroy'行为
    我们额外增加一个'highlight' 方法
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)

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

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

这里使用了 ModelViewSet,从而实现了默认的读写操作方法。

要实现一个自定义的操作,比如 highlight,需要为其定义一个方法,并且加上装饰器 @detail_route。该装饰器可用在所有非标准 create/update/delete 风格的自定义 API 上。

使用了 @detail_route 的自定义方法的 API 默认只响应 GET 请求,如果要响应 POST 等请求,需要在装饰器的 methods 参数中指定。自定义方法的 API,其 URL 默认就是函数名本身,如 highlight,要想修改,需要在 @detail_route 装饰器的 url_path 参数中指定。

1.2 手动将 ViewSet 绑定到 URL

通过手动将 ViewSet 转成具体的 View,以了解 ViewSet 的工作原理。

# quickstart/urls.py

# -*- coding:utf-8 -*-

from django.conf.urls import url
import quickstart.views as views
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework import renderers

app_name = 'qk'

snippet_list = views.SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})

snippet_detail = views.SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})

snippet_highlight = views.SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])

user_list = views.UserViewSet.as_view({
    'get': 'list'
})

user_detail = views.UserViewSet.as_view({
    'get': 'retrieve'
})

urlpatterns = [
    url(r'api/$', views.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'),

]
urlpatterns = format_suffix_patterns(urlpatterns)

现在,系统应该能和之前一样正常运行。

1.3 使用 Router 进一步重构

将 ViewSet 自动转成具体的 View 并绑定到 URL 的操作可以由 Router 自动完成。

# tutorial/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include

from quickstart import views
from rest_framework.routers import DefaultRouter

# 创建路由器并注册我们的视图。
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    # url(r'^user/', views.TestView.as_view()),
    # url(r'^', include('quickstart.urls', namespace='qk')),
    url(r'^', include(router.urls)),
]

urlpatterns += [
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
# quickstart/urls.py

# -*- coding:utf-8 -*-

from django.conf.urls import url
import quickstart.views as views
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework import renderers

app_name = 'qk'


snippet_list = views.SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})

snippet_detail = views.SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})

snippet_highlight = views.SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])

user_list = views.UserViewSet.as_view({
    'get': 'list'
})

user_detail = views.UserViewSet.as_view({
    'get': 'retrieve'
})

urlpatterns = [
    # url(r'api/$', views.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'),

]
# urlpatterns = format_suffix_patterns(urlpatterns)

Router 还自动生成了 api_root,并为 URL 加上了后缀功能,从而无需定义 api_view 视图及使用 format_suffix_patterns 了。


评论(0 ) 点赞(14)


暂未登录,请登录之后发表评论。 QQ