REST framework (組件源碼流程分析)


閱讀目錄前端

1、APIView & View數據庫

2、組件源碼流程django


1、APIView & View

  • View
    • 路徑:django.views.View
    • 使用:
      • urls: path('xxx/', views.xxxx.as_view(), name='xxx')
      • 視圖:class xxxx(View):
  • ApiView
    • 路徑:from rest_framework.views import APIView
    • 使用:
      • urls: path('xxx/', views.xxAPI.as_view(), name='xxx')
      • 視圖:class xxAPI(APIView):
    • APIView繼承View,重寫as_view(),增長擴展配置

 

2、組件源碼流程分析 

1. APIView源碼分析

1.路由:url(r'^books/$', views.BookView.as_view(),name="books") # View下的view

    2.請求:books/一旦被訪問 執行APIView.as_view() -> APIView: dispatch() view = super(APIView, cls).as_view(**initkwargs) 3.def dispatch():      # APIView
        # request加工
        request = self.initialize_request(request, *args, **kwargs) 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 ) # 構建request對象
        self.request=Request(request) class Request(object):      self._request = request  # 原request
                      def query_params(self):        return self._request.GET      def data(self):        return post.data # post請求數據
 self.request._request self.request.GET # get
       self.request.data # POST PUT
        
       # 初始化組件信息
       self.initial(request, *args, **kwargs) 分發----if get請求: 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) # 視圖: self.get(request, *args, **kwargs) 
       return response 4.csrf_exempt(view)   #排除csrf

1.1 APIView().initial() 流程

def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """
    # 1.肯定請求是否包含「.json」樣式格式後綴
    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) def perform_content_negotiation(self, request, force=False): """ Determine which renderer and media type to use render the response. """
            # 2.渲染器
            renderers = self.get_renderers()   # [renderer() for renderer in self.renderer_classes]
            # 3.協商類
            conneg = self.get_content_negotiator() # if not getattr(self, '_negotiator', None):
            # self._negotiator = self.content_negotiation_class()
            # return self._negotiator

            try: # 選擇渲染器
                return conneg.select_renderer(request, renderers, self.format_kwarg) except Exception: if force: return (renderers[0], renderers[0].media_type) raise
    # 調用request對象__setattr__賦值
    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) def determine_version(self, request, *args, **kwargs): """ If versioning is being used, then determine any API version for the incoming request. Returns a two-tuple of (version, versioning_scheme) """
            if self.versioning_class is None: return (None, None) # 4.version組件
            scheme = self.versioning_class() # api_settings.DEFAULT_VERSIONING_CLASS
            return (scheme.determine_version(request, *args, **kwargs), scheme # 調用request對象__setattr__賦值
    request.version, request.versioning_scheme = version, scheme

# Ensure that the incoming request is permitted # 5.認證組件 self.perform_authentication(request) # 默認執行 def perform_authentication(self, request): request.user #執行request的user,這是的request已是加工後的request了
  @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  #返回user

    # 執行self._authenticate() 開始用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
    def _authenticate(self):
   """   Attempt to authenticate the request using each authentication instance   in turn.    """    #循環對象列表   for authenticator in self.authenticators:   try:    #執行每個對象的authenticate 方法    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 #返回一個元組,user,和auth,賦給了self,    # 只要實例化Request,就會有一個request對象,就能夠request.user,request.auth了    return   self._not_authenticated() 

     # 若是沒有認證成功
     def _not_authenticated(self):
  """
          Set authenticator, user & authtoken representing an unauthenticated request.
          Defaults are None, AnonymousUser & None.
          """
          #若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
          self._authenticator = None  #
          if api_settings.UNAUTHENTICATED_USER:
              self.user = api_settings.UNAUTHENTICATED_USER() # 默認值爲:匿名用戶AnonymousUser
          else:
              self.user = None  # None 表示跳過該認證
          if api_settings.UNAUTHENTICATED_TOKEN:
              self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默認值爲:None
          else:
              self.auth = None
        # (user, token)
        # 表示驗證經過並設置用戶名和Token;
        # AuthenticationFailed異常
 
 
  # 6.權限組件
  self.check_permissions(request)
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
#if request.authenticators and not request.successful_authenticator:
# raise exceptions.NotAuthenticated()
# raise exceptions.PermissionDenied(detail=message)
  # 7.頻率組件
  self.check_throttles(request)
def check_throttles(self, request):
"""
Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
"""
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait()) # exceptions.Throttled(wait)
 

APIView().dispatch()  執行結束分發至視圖,緊接着執行視圖中的 def get(request, *args, **kwargs) ,def post(request, *args, **kwargs) 等json

2. 視圖執行流程

操做數據:以Book表爲例 class BookView(APIView): # 查看全部書籍
        def get(self,request): book_list=Book.objects.all() bs=BookModelSerializers(book_list,many=True,context={'request': request}) return Response(bs.data) # 添加一本書籍
        def post(self,request): # post請求的數據
            bs=BookModelSerializers(data=request.data) if bs.is_valid(): print(bs.validated_data) bs.save()# create方法
                return Response(bs.data) else: return Response(bs.errors) class BookDetailView(APIView): # 查看一本書籍
        def get(self,request,id): book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,context={'request': request}) return Response(bs.data) # 更新一本書籍
        def put(self,request,id): book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) # 刪除某一本書籍
        def delete(self,request,id): Book.objects.filter(pk=id).delete() return Response()
操做數據:以Book表爲例

分析:獲取全部書籍,執行get方法查詢數據庫,返回對象/queryset交給自定製序列化類,分頁後Response返回給前端,這個過程當中DRF組件體現:api

  • 序列化組件  
  • 分頁組件 
  • 渲染器 

3、總結

根據上面的分析,總結DRF包含的幾大組件以下:app

請求進來:ide

  1. 路由(可自定製路由)
  2. 版本
  3. 認證
  4. 權限
  5. 頻率
  6. 獲取數據(解析器)請求頭解析
  7. 序列化
  8. 分頁
  9. 渲染器
  10. 視圖   # DRF視圖不僅有APIView

 本文基於APIView源碼流程分析總結DRF幾大組件,組件的使用請見 REST framework (組件使用)源碼分析

相關文章
相關標籤/搜索