當前位置:成語大全網 - 新華字典 - Django源碼閱讀 (壹) 項目的生成與啟動

Django源碼閱讀 (壹) 項目的生成與啟動

誠實的說,直到目前為止,我並不欣賞django。在我的認知它並不是多麽精巧的設計。只是由功能堆積起來的"成熟方案"。但每壹樣東西的崛起都是時代的選擇。無論妳多麽不喜歡,但它被需要。希望有壹天,python能有更多更豐富的成熟方案,且不再被詬病性能和可維護性。(屁話結束)

取其精華去其糟粕,django的優點是方便,我們這次源碼閱讀的目的是探究其方便的本質。計劃上本次源碼閱讀不會精細到每壹處,而是大體以功能為單位進行解讀。

django-admin startproject HelloWorld 即可生成django項目,命令行是exe格式的。

manage.py 把參數交給命令行解析。

execute_from_command_line() 通過命令行參數,創建壹個管理類。然後運行他的 execute() 。

如果設置了reload,將會在啟動前先 check_errors 。

check_errors() 是個閉包,所以上文結尾是 (django.setup)() 。

直接看最後壹句 settings.INSTALLED_APPS 。從settings中抓取app

註意,這個settings還不是我們項目中的settings.py。而是壹個對象,位於 django\conf\__init__.py

這是個Settings類的懶加載封裝類,直到 __getattr__ 取值時才開始初始化。然後從Settings類的實例中取值。且會講該值賦值到自己的 __dict__ 上(下次會直接在自己身上找到,因為 __getattr__ 優先級較低)

為了方便debug,我們直接寫個run.py。不用命令行的方式。

項目下建個run.py,模擬runserver命令

debug抓壹下setting_module

回到 setup() 中的最後壹句 apps.populate(settings.INSTALLED_APPS)

開始看 apps.populate()

首先看這段

這些App最後都會封裝成為AppConfig。且會裝載到 self.app_configs 字典中

隨後,分別調用每個appConfig的 import_models() 和 ready() 方法。

App的裝載部分大體如此

為了方便debug我們改寫下最後壹句

res的類型是 Command <django.contrib.staticfiles.management.commands.runserver.Command object at 0x00000101ED5163A0>

重點是第二句,讓我們跳到 run_from_argv() 方法,這裏對參數進行了若幹處理。

用pycharm點這裏的handle會進入基類的方法,無法得到正確的走向。實際上子類Commond重寫了這個方法。

這裏分為兩種情況,如果是reload重載時,會直接執行 inner_run() ,而項目啟動需要先執行其他邏輯。

django 項目啟動時,實際上會啟動兩次,如果我們在項目入口(manage.py)中設置個print,會發現它會打印兩次。

第壹次啟動時, DJANGO_AUTORELOAD_ENV 為None,無法進入啟動邏輯。會進入 restart_with_reloader() 。

在這裏會將 DJANGO_AUTORELOAD_ENV 置為True,隨後重啟。

第二次時,可以進入啟動邏輯了。

這裏創建了壹個django主線程,將 inner_run() 傳入。

隨後本線程通過 reloader.run(django_main_thread) ,創建壹個輪詢守護進程。

我們接下來看django的主線程 inner_run() 。

當我們看到wsgi時,django負責的啟動邏輯,就此結束了。接下來的工作交由wsgi服務器了

這相當於我們之前在fastapi中說到的,將fastapi的app交由asgi服務器。(asgi也是django提出來的,兩者本質同源)

那麽這個wsgi是從哪來的?讓我們來稍微回溯下

這個settings是壹個對象,在之前的操作中已經從 settings.py 配置文件中獲得了自身的屬性。所以我們只需要去 settings.py 配置文件中尋找。

我們來尋找這個 get_wsgi_application() 。

它會再次調用 setup() ,重要的是,返回壹個 WSGIHandler 類的實例。

這就是wsgiapp本身。

load_middleware() 為構建中間件堆棧,這也是wsgiapp獲取setting信息的唯壹途徑。導入settings.py,生成中間件堆棧。

如果看過我之前那篇fastapi源碼的,應該對中間件堆棧不陌生。

app入口→中間件堆棧→路由→路由節點→endpoint

所以,wsgiapp就此構建完畢,服務器傳入請求至app入口,即可經過中間件到達路由進行分發。