Django Rest Framework(二 認證源碼流程)

1、CBV回顧

 

class TestView(APIView): def dispatch(self, request, *args, **kwargs): """ 請求到來以後,都要執行dispatch方法,dispatch方法根據請求方式不一樣觸發 get/post/put等方法 注意:APIView中的dispatch方法有好多好多的功能 """
        return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET請求,響應內容') def post(self, request, *args, **kwargs): return Response('POST請求,響應內容') def put(self, request, *args, **kwargs): return Response('PUT請求,響應內容')

2、使用restful時流程

總體:自建類繼承APIView ,APIView又繼承View類django

入口:CBV/FBV入口都是urls,由此出發restful

分發:urls 裏邊使用as_view方法,通過處理到達dispatch方法,在這作分發ide

終點:執行自定義的認證類post

3、圖示

 

4、執行詳細流程

  • url(r'^test/', TestView.as_view())

進入as_view方法 位置···\site-packages\rest_framework\views.py
  super(APIView, cls).as_view(**initkwargs) 
  調用父類View的as_view() 位置 \site-packages\django\views\generic\base.py
    最終返回 return self.dispatch(request, *args, **kwargs)
this

  • self.dispatch

self是TestView ,沒有dispatch方法,繼續向APIView找
APIView裏邊有 url

  • def dispatch()

  ···/site-packages/rest_framework/views.py APIView  def dispatch()spa

 1     def dispatch(self, request, *args, **kwargs):  2  ···  3         # 在這對request作了一下加工
 4         request = self.initialize_request(request, *args, **kwargs) # -->> 對應步驟四、5 -->> 對應步驟四、5
 5  ···  6         # request是豐富後的新request
 7         self.initial(request, *args, **kwargs) # -->> 對應步驟六、七、八、9 -->> 對應步驟六、七、八、9
 8  ···  9         # 根據請求反射取屬性,根據method作分發
10         handler = getattr(self, request.method.lower(), 11  self.http_method_not_allowed) 12         response = handler(request, *args, **kwargs)
  • initialize_request()

  initialize_request() ···/site-packages/rest_framework/views.pyrest

 1     def initialize_request(self, request, *args, **kwargs):  2         """
 3  Returns the initial request object.  4  原始request進來,出去是 含request在內的大元祖  5  request基礎上增長了parsers、authenticators、negotiator、parser_context四個屬性  6  四個屬性又對應着四個方法,點擊方法進入查看  7         """
 8         parser_context = self.get_parser_context(request)  9         
10         # 把原始的request參數豐富了,利用的是Request類實例化 
11         return Request( 12  request, 13             parsers=self.get_parsers(), 14             authenticators=self.get_authenticators(), #獲取用戶認證類
15             negotiator=self.get_content_negotiator(), 16             parser_context=parser_context 17         )
  • Request()

  Request() ···\site-packages\rest_framework\request.pycode

 1 class Request(object):  2     def __init__(self, request, parsers=None, authenticators=None,  3                  negotiator=None, parser_context=None):  4  ···  5         self._request = request  #原始request的調用方式
 6         self.parsers = parsers or ()  7         self.authenticators = authenticators or ()  8         self.negotiator = negotiator or self._default_negotiator()  9         self.parser_context = parser_context 10         self._data = Empty 11         self._files = Empty 12         self._full_data = Empty 13         self._content_type = Empty 14         self._stream = Empty 15     # 以上是封裝的參數
16     # 此外,還封裝了不少方法,一些加了@property
17     # 先看涉及到的parsers、authenticators、negotiator、parser_context 對應的方法
18 
19     def get_parsers(self): 20         """
21  Instantiates and returns the list of parsers that this view can use. 22         """
23         return [parser() for parser in self.parser_classes] 24 
25     def get_authenticators(self): 26         """
27  Instantiates and returns the list of authenticators that this view can use. 28  在這把用戶認證類(對象)娶到手了 29         """
30         return [auth() for auth in self.authentication_classes] 31 
32 
33     def get_content_negotiator(self): 34         """
35  Instantiate and return the content negotiation class to use. 36         """
37         if not getattr(self, '_negotiator', None): 38             self._negotiator = self.content_negotiation_class() 39         return self._negotiator 40 
41     def get_parser_context(self, http_request): 42         """
43  Returns a dict that is passed through to Parser.parse(), 44  as the `parser_context` keyword argument. 45         """
46         # Note: Additionally `request` and `encoding` will also be added
47         # to the context by the Request object.
48         return { 49             'view': self, 50             'args': getattr(self, 'args', ()), 51             'kwargs': getattr(self, 'kwargs', {}) 52         }
class Request(object)
  • dispatch()到 initial()

APIView類中:orm

def initial(self, request, *args, **kwargs): self.perform_authentication(request) # 調用認證的方法
  • initial()到perform_authentication()

APIView類中:

def perform_authentication(self, request): # 只有這一句
        request.user

認證走到這了,只有一行request.user 說明是user方法裏作的認證
此時request 是新的request 也就是Request() 實例化出來的對象
 進去 Request() 找user方法 看看幹了啥
 從APIView() 跳到 Request() 裏邊了

  • Request() -- user()方法

 @property def user(self): if not hasattr(self, '_user'): with wrap_attributeerrors(): # 執行當前類的_authenticate() 方法
 self._authenticate() return self._user
  • user() 跳到 _authenticate()

  Request() -- _authenticate()方法

def _authenticate(self): # 循環認證全部的類
        for authenticator in self.authenticators: try: # authenticators是上邊四、5兩步取出來的 用戶認證類對象 列表
                # authenticator對象由用戶認證類實例化而來,用戶認證類確定要支持authenticate()方法
                # 這個方法就是給咱們留的鉤子呀,藏得真TM深
                user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise

            if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple return self._not_authenticated()

 

整個探索過程當中最重要的是,搞清楚類之間的繼承和引用關係,以及不一樣類包含相同方法時,到底要執行哪一個類。

遇到實在分不清的,能夠打斷點看它到底走的哪。不過打斷點的前提是對程序總體流程有所瞭解

相關文章
相關標籤/搜索