REST 框架包含了处理ViewSet
的抽象,这样开发者就可以专注于API的状态和交互,而不用去管URL的构造,URL会按照
公共约定自动构造。
ViewSet
类和View
类差不多,不同的是ViewSet
提供如read
,update
等方法,而不是get
或是put
。
一个ViewSet
类只绑定一组方法处理程序,当它被实例化为一组views
时,通常用一个Router
类来处理复杂的url。
重构代码以使用ViewSets
首先将我们现有的UserList
和UserDetail
重构合并为UserViewSet
。
编辑views.py
from rest_framework import viewsets
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
这个ViewSet提供`list`和`detail`两个功能
"""
queryset = User.objects.all()
serializer_class = UserSerializer
这里我们使用的ReadOnlyModelViewSet
类会提供默认的只读操作。
像以前一样,我们依然定义queryset
和serializer_class
属性,只不过之前需要在两个类里面定义,现在只需要定义一遍。
接下来我们将现有的SnippetList
, SnippetDetail
, SnippetHighlight
重构合并为SnippetViewSet
。
编辑views.py
from rest_framework.decorators import detail_route
from rest_framework.response import Response
class SnippetViewSet(viewsets.ModelViewSet):
"""
这个ViewSet自动了`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
类会提供默认的读写操作。
注意,我们在此同样使用了@detail_route
装饰器来创建一个额外的功能,名为highlight
,当标准的create
, update
, delete
不够用时,这个装饰器能够用来添加任何额外的功能。
使用@detail_route
装饰器定制的额外功能会默认使用GET
请求,我们可以在装饰器的参数内定义methods
参数来使用如POST
等等的其它请求。
默认情况下,这种定制的额外功能会使用和方法名同名的url,如想要使用与方法名不同的url,可以在detail_route
装饰器中定义url_path
参数。
将ViewSets与URLs绑定
编辑urls.py
from rest_framework import renderers
from snippets.views import api_root
from snippets.views import SnippetViewSet
from snippets.views import UserViewSet
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'
})
此时我们通过将http请求方式绑定到views的方法,从ViewSet
类创建了一系列views。
接下来我们将这些views注册到url中
编辑urls.py
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = format_suffix_patterns([
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')
])
使用Router
类
因为我们使用的是ViewSet
类而不是View
类,实际上我们不需要自己去设计URL。
通过使用Router
类,我们只需要将合适的views注册到Router
中,其它的事情就让它自动生成吧。
重写urls.py
from django.conf.urls import url
from django.conf.urls import include
from snippets import views
from rest_framework.routers import DefaultRouter
# 创建一个router并将viewsets注册上去
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
DefaultRouter
类自动提供了根节点的url,所以我们不再需要单独去写。
关于
本人是初学Django REST framework,Django REST framework 学习纪要系列文章是我从官网文档学习后的初步消化成果,如有错误,欢迎指正。
学习用代码Github仓库:shelmingsong/django_rest_framework
本文参考的官网文档:Tutorial 6: ViewSets & Routers
博客更新地址
- 宋明耀的博客 [ 第一时间更新 ]
- 知乎专栏 Python Cookbook
- 简书 流月0的文章