Django-restframework 之認證源碼分析

Django-restframework 源碼分析之認證

前言

最近學習了 django 的一個 restframework 框架,對於裏面的執行流程產生了興趣,通過昨天一夜初步搞清楚了執行流程(部分方法還不太清楚),因而想詳細的總結一下當來一個請求時,在該框架裏面是如何執行的?python

啓動項目時

昨天在調試django時,發如今 APIView 中打的斷點沒有斷下來,而是打在 View 中的斷點斷下來了,調試了不少次,最後發現,在 django 項目啓動時,會首先加載 urls 中的文件,執行 views 中類的 as_view方法,實際上是繼承自 APIView 的,APIView 繼承自 django 原生 View 的as_view 方法。django

裏面一個參數叫 pattern_name,對應的值是admin:auth_group_change,以下圖所示:bootstrap

目前還不清楚這裏面的具體流程是什麼,可是並不妨礙閱讀以後的源碼,在這隻要清楚一點,在 Django 項目啓動時,路由所對應的CBV裏面的相關方法的內存地址已經獲取到。這樣作的好處就是提升效率,壞處可能有一點點,會提高性能的消耗。api

具體路由和邏輯代碼

在這裏假設來一個 GET 請求,urls 和 views裏面的代碼以下:框架

# urls.py

url(r'^book/(?P<id>\d+)/', views.Book.as_view()),
# views.py
class Book(APIView):

    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, id):

        response = {'status': 100, 'msg': None}

        book = models.Book.objects.filter(pk=id).first()
        book_ser = BookSerib(book, many=False)
        print('book_ser.data', book_ser.data)
        response['books'] = book_ser.data
        response['msg'] = '獲取圖書成功'
        print('response', response)
        return Response(response)

urls 裏面就是一個典型的 CBV 的路由配置,在 views 中一個是路由分發方法,一個是獲取單本圖書信息(經過 id)。函數

as_view 具體執行流程

在項目啓動時,相應的函數內存地址已經獲取到,那麼具體是怎麼獲取到的呢?源碼分析

在上面的代碼中能夠看到 Book類是繼承自APIView類的,因此在路由配置裏面執行的as_view方法若是Book類沒有重寫,那麼執行的就是按照mro列表順序查找到的第一個方法,在這裏執行的是APIView類中的as_view方法。性能

查看該源碼以下:學習

APIView類的父類是View類,查看該類的as_view方法,源碼以下:url

具體as_view就是將view函數的內存地址返回,以便請求來時直接調用。

initkwargs這個參數應該是由 django 內部傳的一些參數,以下所示:

請求到來時

由於通過 django 先執行了as_view返回view的內存地址,因此會直接執行view函數,以下:

在這裏該 self 因爲是 繼承自APIView類的Book類的對象,因此dispatch方法首先去自身找,以後去父類找,在APIView類中找到dispatch方法,源碼以下:

initialize_request方法:

源碼以下:

在實例化Request對象時,authenticators參數須要在認證時使用,因此先把這個參數的值找出來。步驟以下:

  • 調用 self.get_authenticators

  • 找到 self.authentication_classes

  • 找到 api_settings,才能找到DEFAULT_AUTHENTICATION_CLASSES

  • DEFAULT和IMPORT_STRINGS參數
  1. DEFAULT參數

  1. IMPORT_STRINGS參數

  • 實例化 APISettings 對象

  • 經過__getattr__方法獲取值

  • 執行perform_import方法

  • 執行import_from_string

  • 執行import_module

  • 執行_bootstrap._gcd_import

  • 執行_sanity_check

  • _sanity_check返回,執行_find_and_load方法

  • 因此經過__getattr__的到的是一個列表,裏面是兩個類,分別是[rest_framework_authentication_SessionAuthentication, rest_framework_authentication_BasicAuthentication]

到這裏,initialize_request方法執行結束,獲得一個通過 Request 類實例化的 request 對象,該對象裏面含有原生 request 對象,能夠經過request._request取到。

initial 方法:

源碼以下:

這裏傳入的request參數是通過Request封裝後的參數

  • 執行get_format_suffix

執行完這個方法,self_format_kwarg = None

  • 執行perform_content_negotiation

  1. 執行self.get_renders

  1. 執行self.get_content_negotiator

  1. 執行 conneg.select_renderer方法

未完待續…...

相關文章
相關標籤/搜索