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.py3d

 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.pyrest

 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類中:code

    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()

 

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

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

相關文章
相關標籤/搜索