教程 6: ViewSets & Routers
REST 框架包含对于ViewSets的抽象处理,其允许开发者专注于API模块状态与交互,基于约定,使得URL自动处理。 ViewSet 跟 View 相仿, 除了提供的read与update操作以外,它没有get与put操作。 ViewSet 只在最后绑定一组方法处理程序, 当实例化一组 views, 特别实在使用Router ,其可以处理 复杂的URL导向适合的配置。
用 ViewSets重构
让我们定义当前的视图,并重构viewset
首先 让我们把 UserList 和 UserDetail 视图合并到 UserViewSet中. 移除这2个视图, 用一单一class替代它:
from rest_framework import viewsetsclass UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
This viewset automatically provides `list` and `detail` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
我们已经使用ReadOnlyModelViewSet class,其自动提供默认的 'read-only' 操作. We're still setting thequeryset and serializer_class attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes. 之后我们移除 SnippetList, SnippetDetail 和 SnippetHighlight视图类. 我们溢出这3个视图并合并到一个class中。
from rest_framework.decorators import linkclass SnippetViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
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 以取得 完备的读写操作. Notice 我们也使用 @link 装饰器 以定义一方法 highlight. 这个装饰器能被用于任何不适合create/update/delete方法的自定义结点. 使用@lin装饰器以响应GET请求. 如果需要响应POST请求,我们同样可以使用 @action装饰器 .
将ViewSets 与 URLs 进行绑定
只有当我们定义URLConf时,处理程序的方法才绑定到操作上。我们首先明确ViewSets创建一组视图。
在urls.py 文件中我们绑定把 ViewSet 绑定到 具体视图中.
from snippets.views import SnippetViewSet, UserViewSetfrom 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'
})
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')
))
Using Routers
重写 urls.py 文件.
from django.conf.urls import patterns, url, includefrom snippets import views
from rest_framework.routers import DefaultRouter
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# The API URLs are now determined automatically by the router.
# Additionally, we include the login URLs for the browseable API.
urlpatterns = patterns('',
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)
Registering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.
The DefaultRouter class we're using also automatically creates the API root view for us, so we can now delete the api_rootmethod from our views module.