Django Rest Framework(二 认证源码流程)
一、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请求,响应内容')
二、使用restful时流程
整体:自建类继承APIView ,APIView又继承View类
入口:CBV/FBV入口都是urls,由此出发
分发:urls 里边使用as_view方法,经过处理到达dispatch方法,在这做分发
终点:执行自定义的认证类
三、图示
四、执行详细流程
-
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)
-
self.dispatch
self是TestView ,没有dispatch方法,继续向APIView找
APIView里边有
-
def dispatch()
···/site-packages/rest_framework/views.py APIView def dispatch()
1 def dispatch(self, request, *args, **kwargs): 2 ··· 3 # 在这对request做了一下加工 4 request = self.initialize_request(request, *args, **kwargs) # -->> 对应步骤4、5 -->> 对应步骤4、5 5 ··· 6 # request是丰富后的新request 7 self.initial(request, *args, **kwargs) # -->> 对应步骤6、7、8、9 -->> 对应步骤6、7、8、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.py
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.py
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 }
-
dispatch()到 initial()
APIView类中:
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是上边4、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()
整个探索过程中最重要的是,搞清楚类之间的继承和引用关系,以及不同类包含相同方法时,到底要执行哪个类。
遇到实在分不清的,可以打断点看它到底走的哪。不过打断点的前提是对程序整体流程有所了解