drf源码解析
drf源码解析
CBV下根据请求方式执行不同方法
django
从url 出发,
re_path(r"^student/", views.StudentView.as_view())
,通过as_view可以看到里面有一个view方法,返回值是self.dispatch(request, *args, **kwargs)
, dispatch里是通过getatter反射来实现这个功能的def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: # 通过反射实现不同的请求方式执行不同的函数 handler = getattr( self, request.method.lower(), self.http_method_not_allowed ) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
drf 框架
其实和django类似,drf的APIView类继承了django的view类,在这个类里重写了dispatch方法,会调用
request = self.initialize_request(request, *args, **kwargs)
对request进行包装,同时也是根据反射去实现根据不同请求执行不同方法的功能def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs # 加工原生request request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) if request.method.lower() in self.http_method_names: 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
drf认证源码
在self.initlialize_request中获取认证对象集合
通过
APIView
找到dispatch
, 会看到他是继承了django
的view
的,重写了dispatch
,并且在这个方法里,会对django
的request
进行处理,这个时候,我们在cbv
里看到的self.request
其实不是原本的django request
(其实原本的在处理后也会保存在drf
的request
中) 在执行drf dispatch
对request进行包装的时候我们可以看到self.initialize_request
里的代码有一句就是通过get_authenticators
里去获取认证的对象列表, 按照这个思路,如果我们在自己的view 不定义authentication_classes
那么就会使用默认的认证方法,如果我们自定义用户认证话,只需要在view指定我们的authentication_classes
就行1.1
drf dispatch
def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs # 加工原生request request = self.initialize_request(request, *args, **kwargs) # self.initialize_request #self.parsers = parsers or () #self.authenticators = authenticators or () #self.negotiator = negotiator or self._default_negotiator() #self.parser_context = parser_context #self._data = Empty #self._files = Empty #self._full_data = Empty #self._content_type = Empty #self._stream = Empty # 获取原生request # self.request._request # self._request = request # 获取认证对象列表 # self.authenticators self.request = request self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: 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
1.2
initialize_request
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), 获取 negotiator=self.get_content_negotiator(), parser_context=parser_context )
- 然后再
dispatch
中继续向下,执行到initial中的时候,会有一个perform_authentication
方法,这个方法会执行request.user
,这个时候看request中寻找user属性。发现时用property
来将类方法变为属性的。在这个方法里面会调用self._authenciate()
进行认证,通过循环之前获取到的认证对象集合,调用每个对象里的authenciate
方法来进行认证,如果认证成功返回一个元组,如果认证失败,抛出内置的认证失败异常。所以我们自定义认证,其实就是实现authenciate方法2.1 dispatch
def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs # 加工原生request request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: # 这里进行认证 self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: 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
2.2
initial
def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """ self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request) request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use. version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted # 调用perform_authentication这个函数执行requst.user 获取登录信息 # request.user 是在包装request时添加的属性,具体可以看initialize_request里时怎么实现的 self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
2.3
perform_authentication
def perform_authentication(self, request): """ Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication will instead be performed lazily, the first time either `request.user` or `request.auth` is accessed. """ request.user
2.4
request.user
这时回头看drf
包装request时怎么添加requet.user
的
- 在
initialize_request
中看到返回值时Request
对象,这个对象里有个实例方法- 通过property 将方法变为属性,调用request的_authenticate方法
@property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user
2.5 _authenticate方法中,通过遍历认证集合,调用authenticat方法获得认证结果
- 如果认证成功返回元组
- 如果认证失败抛出认证失败异常
def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ for authenticator in self.authenticators: try: 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
2.6 上一步调用的authenticate方法
- 返回值是一个元组
class ForcedAuthentication: """ This authentication class is used if the test client or request factory forcibly authenticated the request. """ def __init__(self, force_user, force_token): self.force_user = force_user self.force_token = force_token def authenticate(self, request): return (self.force_user, self.force_token)
2.7 所以如果要自定义认证方式,需要实现authenticate就可以了