ViewSets & Routers
参考链接:
http://www.weiguda.com/blog/24/
http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/
http://stackoverflow.com/questions/20550598/django-rest-framework-could-not-resolve-url-for-hyperlinked-relationship-using
django-rst-framework为我们提供了ViewSet类, ViewSet为我们提供了默认的URL结构, 使得我们能更专注于API本身. ViewSet类与View类几乎是相同的, 但提供的是read或update, 而不是http动作get或put.
一个ViewSet类最后仅仅绑定在一套method handlers上,当它被实例化成一套views时,用Router类可以处理复杂的URL配置
ViewSet类在实例化后, 通过Router类, 最终将URL与ViewSet方法绑定. 接下来我们使用ViewSet代替之前的View.
【1】用ViewSets重构
把UserList和UserDetail重构成一个UserViewSet
from rest_framework import viewsets class UserViewSet(viewsets.ReadOnlyModelViewSet): """ This viewset automatically provides `list` and `detail` actions. """ queryset = User.objects.all() serializer_class = UserSerializer
把MyLessonList,MyLessonDetail,MyLessonHighlight重构成一个MyLessonViewSet
from rest_framework.decorators import detail_route class MyLessonViewSet(viewsets.ModelViewSet): """ This viewset automatically provides 'list', 'create', 'retrieve', 'update' and 'destroy' actions. Additionally we also provide and extra 'highlight' action. """ queryset = MyLesson.objects.all() serializer_class = MyLessonSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,) @detail_route(renderer_classes=[renderers.StaticHTMLRenderer]) def highlight(self,request,*args,**kwargs): myLesson = self.get_object() return Response(myLesson.highlighted) def perform_create(self,serializer): serializer.save(owner=self.request.user)
使用@detail_route装饰器来创建一个自定义操作highlight,可以加methods参数,限定http方法
,默认是get,url是默认生成的,如果想自定义,可以加url_path参数
【2】绑定ViewSets到特定的URLS
from django.conf.urls import url,include from myLesson.views import MyLessonViewSet,UserViewSet,api_root from rest_framework import renderers from rest_framework.urlpatterns import format_suffix_patterns myLesson_list = MyLessonViewSet.as_view({ 'get':'list', 'post':'create' }) myLesson_detail = MyLessonViewSet.as_view({ 'get':'retrieve', 'put':'update', 'patch':'partial_update', 'delete':'destroy' }) myLesson_highlight = MyLessonViewSet.as_view({ 'get':'highlight' },renderer_classes=[renderers.StaticHTMLRenderer]) user_list = UserViewSet.as_view({ 'get':'list' }) user_detail = UserViewSet.as_view({ 'get':'retrieve' }) urlpatterns = [ url(r'^$',api_root), url(r'^users/$',user_list,name='user-list'), url(r'^users/(?P<pk>[0-9]+)/$',user_detail,name='user-detail'), url(r'^myLesson/$',myLesson_list,name='myLesson-list'), url(r'^myLesson/(?P<pk>[0-9]+)/$',myLesson_detail,name='myLesson-detail'), url(r'^myLesson/(?P<pk>[0-9]+)/highlight/$',myLesson_highlight,name='myLesson-highlight'), ] urlpatterns = format_suffix_patterns(urlpatterns)
我们ViewSet创建了很多VIew,通过绑定http方法给每个view特定的动作
【3】使用Routers
我们实际上是没必要设计URL的,可以使用Routers自动化的配置,DefaultRouter可以自动化创建根view,所以可以删除api_root
from django.conf.urls import url, include from 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.MyLessonViewSet) router.register(r'users', views.UserViewSet) # The API URLs are now determined automatically by the router. # Additionally, we include the login URLs for the browsable API. urlpatterns = [ url(r'^', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) ]
【4】权衡views和viewsets
viewsets自动创建URL,减少代码,但是使用views更加精确
【5】修改完代码,myLesson和user页面均报错
修改方式,在serializers.py中将有view_name的serializers.HyperlinkedIdentityField行都去掉。用Router方式自自动生成url,不清楚view_name怎么定义。因此highlight做不了超链接,调了两天不清楚怎么办,搁置了。。。。
url = serializers.HyperlinkedIdentityField(view_name="user-detail") myLesson = serializers.HyperlinkedRelatedField(many=True,view_name='MyLesson-detail' ,read_only=True)