一、视图类
#bookview是一个视图类,继承自ModelViewSet class BookView(ModelViewSet): throttle_classes = [VisitThrottle2] queryset = models.Book.objects.all() serializer_class = BookModelSerializer
ModelViewSet
ModelViewSet: class ModelViewSet(mixins.CreateModelMixin, # 实现了post添加逻辑 mixins.RetrieveModelMixin, # 实现了获取具体某一本书的逻辑 mixins.UpdateModelMixin, # 实现了put编辑的逻辑 mixins.DestroyModelMixin, # 实现了删除一本书的逻辑 mixins.ListModelMixin, # 实现了获取所有书的逻辑 GenericViewSet): # 提供了APIView和dispatch的功能 ....
由于ModelViewSet继承了多个混合类和通用视图类,所以ModelViewSet提供了.list(),.retrieve(), .create(),.update(),.partial_update(),和.destroy()
因为ModelViewSet继承了GenericViewSet,所以BookView需要提供queryset和serializer_class属性
二、执行流程
1. url:
url(r'books/$',views.BookView.as_view({'get':'list','post':'create'})), url(r'books/(?P<pk>d+)/$',views.BookDetailView.as_view({'get': 'retrieve', 'put':'update', 'delete':'destroy'})),
当django启动的时候,会执行view.BookView.as_view()方法:由于as_view()是从ViewSetMixin中继承而来的,所以url会变为:
url(r'books/$',ViewSetMixin.view), url(r'books/(?P<pk>d+)/$',ViewSetMixin.view),
2.当用户访问books/的时候,会调用执行ViewSetMixin.view并传入request。
class ViewSetMixin(object): """ 他是一个魔法方法 重写`.as_view()‘,以便它接受一个’actions‘关键字, 该关键字执行HTTP方法到资源上的操作的绑定。 例如,要创建一个将“GET”和“POST”方法绑定到“List”和“Create”操作的具体视图. view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """ def view(request, *args, **kwargs): self = cls(**initkwargs) self.action_map = actions # {'get':'list','post':'create'} # {'get': 'retrieve','put':'update','delete':'destroy'} for method, action in actions.items(): # self:ModelViewSet继承的每一个类 action是list create等方法。 # handler是每一个具体的函数名 handler = getattr(self, action) #为属性赋值, self.get = list, self.get = retrieve # 当get请求的时候,真正会执行的是list/retrieve方法 setattr(self, method, handler) # 进行分发,由于以上几个类都没有实现该方法,所以dispatch()执行的是APIView的dispatch() return self.dispatch(request, *args, **kwargs)
3.ViewSetMixin的view主要是把mixins中的list()、create()、retrieve()、等绑定给BookView的get()、post()等。
4.dispatch()
def dispatch(self, request, *args, **kwargs): try: self.initial(request, *args, **kwargs) # get、put、post等请求方法,去list、create、update等,去执行 if request.method.lower() in self.http_method_names: # 这里的self是ViewSetMixin。 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
当客户端请求方式是get的时候,执行BookView的get()方法,实际上是执行的list().因为在ViewSetMixin.view()中,获取minx下的list、create等函数地址,通过settattr()的方式绑给了BookView实例对象
三、总结:
django启动****** url(r'books/$',views.BookView.as_view({'get':'list','post':'create'})), 1 url(r'books/$',ViewSetMixin.view)), 2 一旦用户访问****** books get请求 def view(request, *args, **kwargs): self = cls(**initkwargs) {'get':'list','post':'create'} for method, action in actions.items(): handler = getattr(self, action) #给BookView设置一个属性 BookView.get = ListModelMixin.list setattr(self, method, handler) return self.dispatch(request, *args, **kwargs) url(r'books/$',APIView.dispatch)), 3 if get in self.http_method_names: # 这里的self是ViewSetMixin。 handler = getattr(self, 'get'), --> BookView.get ---> 实际上执行的是 ListModelMixin.list self.http_method_not_allowed) handler返回什么,dispatch返回什么,view返回什么,用户看到什么