pip install djangorestframework
urls.pyhtml
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^dog/', views.DogView.as_view()) ]
views.pypython
from rest_framework.views import APIView class DogView(APIView): def get(self, request, *args, **kwargs): # 這裏的 request 是rest framework加工以後的 request,再也不是原來的request了 print(request) ret = { 'code': 1000, 'msg': 'xxx' } return HttpResponse(json.dumps(ret), status=201) def post(self, request, *args, **kwargs): return HttpResponse('建立Dog') def put(self, request, *args, **kwargs): return HttpResponse('更新Dog') def delete(self, request, *args, **kwargs): return HttpResponse('刪除Dog')
當請求進來,執行 dispatch
,本身沒有找父類 APIView
的 dispatch
django
def dispatch(self, request, *args, **kwargs): ... # 省略的內容 self.kwargs = kwargs # 對原生的request進行加工(豐富了一些功能) ''' # 鼠標點進 initialize_request,返回一個對象 return Request( request, # 這裏纔是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) ''' request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? ...
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) # 返回Request類的一個對象,交給上面的request return Request( request, # 這裏纔是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), # 這裏有個 get_authenticators negotiator=self.get_content_negotiator(), parser_context=parser_context )
問題:若是執行 self.get_authenticators()
,流程是怎樣的,哪裏是入口?json
''' 應該從 DogView 作入口,由於裏面全部傳過去的self,都是 DogView 的對象 DogView 沒有再往父類找 這裏 DogView 沒有 get_authenticators(),而且這個方法應該加了s,猜想應該是個複數 鼠標點進去,查看父類 ''' def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ return [auth() for auth in self.authentication_classes] ''' 能夠看到,返回了一個列表,若是 self.authentication_classes 也是一個列表,而且 self.authentication_classes = [Foo, Bar] 列表裏面是兩個類,則 [auth() for auth in self.authentication_classes] 就是對每一個類進行實例化 因此誰調用這個 get_authenticators 方法,返回的就是 [Foo, Bar] 的對象 即 [Foo(), Bar()] 固然這些目前只是猜想 '''
根據以上猜想,來查看一下api
''' 這裏執行的是 self.authentication_classes,DogView 沒有,去父類查看 ''' class APIView(View): ... # 其餘的內容 authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES ... ''' 這實際上是讀取了 rest_framework的配置文件,是在 APIView中寫的 找的時候優先到 DogView 中查找,沒有再去父類 '''
如今爲 DogView
加上 authentication_classes
,用的就是 DogView
的方法ide
from rest_framework.views import APIView from rest_framework.authentication import BasicAuthentication class DogView(APIView): authentication_classes = [BasicAuthentication, ] # 增長的 def get(self, request, *args, **kwargs): self.dispatch() ret = { 'code': 1000, 'msg': 'xxx' } return HttpResponse(json.dumps(ret), status=201) def post(self, request, *args, **kwargs): return HttpResponse('建立Dog') def put(self, request, *args, **kwargs): return HttpResponse('更新Dog') def delete(self, request, *args, **kwargs): return HttpResponse('刪除Dog')
如今增長了 authentication_classes
,回到上面的 get_authenticators
方法,它返回的是 [BasicAuthentication(), ]
對象,再將它交給 Request
對象post
因此新的 Request
對象目前封裝了兩個值,一個是原生的 request
,一個是 [BasicAuthentication(),]
對象列表this
回到 dispatch
url
def dispatch(self, request, *args, **kwargs): ... # 省略的內容 self.kwargs = kwargs # 對原生的request進行加工(豐富了一些功能) ''' # 鼠標點進 initialize_request,返回一個對象 return Request( request, # 這裏纔是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) 這裏就是 return Request(request, [BasicAuthentication(), ]) ''' request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? ... # 省略的內容
如今是封裝進去了,那麼要取出,該怎麼取呢?(能夠經過 request
點出某個屬性或方法)能夠查看一下 Request
spa
class Request(object): ... # 省略的內容 def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( 'The `request` argument must be an instance of ' '`django.http.HttpRequest`, not `{}.{}`.' .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request # 若是要拿原生的request,須要執行 request._request self.parsers = parsers or () self.authenticators = authenticators or () ... # 省略的內容
# 再回到 dispatch() def dispatch(self, request, *args, **kwargs): ... # 省略的內容 self.kwargs = kwargs # 對原生的request進行加工(豐富了一些功能) ''' # 鼠標點進 initialize_request,返回一個對象 return Request( request, # 這裏纔是原生的request parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) 這裏就是 return Request(request, [BasicAuthentication(), ]) ''' request = self.initialize_request(request, *args, **kwargs) # 獲取原生的request: request._request # 獲取認證類的對象: request.authenticators self.request = request self.headers = self.default_response_headers # deprecate? try: # 將上面的 request 放進來,執行initial,DogView沒有,去父類查找 self.initial(request, *args, **kwargs) ... # 省略的內容
# 來到 initial # 這裏的 request 是封裝後的 request def initial(self, request, *args, **kwargs): ... # 省略的內容 # 這裏的request是帶有原生的request和認證的對象的request # 執行 perform_authentication,DogView 沒有,去父類查找 self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
# 來到 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 request.user
# 經過Request實例化後的對象找到 .user @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() # 注意這裏,去 _authenticate return self._user
# 來到 _authenticate def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ # 這裏的 self.authenticators 就是加工後的request中的第二個值, # 也就是 [BasicAuthentication對象, ] # 這一步就是循環認證類的全部對象 for authenticator in self.authenticators: try: # 拿到上面的[BasicAuthentication對象, ],裏面有個 .authenticate 方法 # 若是這個方法拋出異常,就會被下面的except捕獲到 # 若是沒有異常,則有返回值(返回值有兩種,一個是None,一個是有確切的值) # 有確切的返回值,必須是元組:(request.user, request.auth) # 若是是None,表示本次認證對象不作處理,繼續作下一次的循環處理 # 若是全部對象都爲None,那麼 request.user, request.auth均未賦值 # 等循環玩走最後一步的 self._not_authenticated() # 括號裏的 self 是 request 對象,當前代碼是在 request.py 中 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() # 全部對象都爲None,走這一步
def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. # 若是全部對象都爲None,這裏默認設置一個匿名用戶 Defaults are None, AnonymousUser & None. """ self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # AnonymousUser else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() # None else: self.auth = None
以上即是須要掌握的源碼流程,基於上面的思路,能夠作一個登陸認證的示例
一、使用
BaseAuthentication
,實現 authenticate
方法AuthenticationFailed
異常,表示認證失敗(元素1, 元素2)
,元素1
賦值給 request.user
,元素2
賦值給 request.auth
authentication_classes = [Authentication, ]
REST_FRAMEWORK
二、源碼流程
先走 dispatch()
,對 request
進行封裝,而後執行 initial
,在 initial
中進行認證。執行認證的流程是去找 request.user
,在 request.user
中找以前封裝的 request
的全部認證對象,再循環全部的認證對象,執行 authenticate
方法