一、視圖類
#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返回什么,用戶看到什么
