manage.py 敲下回车之后,Django 到底按什么顺序把 settings、apps、models、urls 一个个拉起来?这篇在项目的每个入口都加了打点,不靠记忆里的源码顺序,直接看时间戳。
命令输出: System check identified no issues (0 silenced). 整个进程 204 ms + 0.0 ms import proj/settings.py(首次访问 settings 才会导入) + 42.2 ms import lab/apps.py(AppConfig 所在模块被导入) + 42.2 ms LabConfig.__init__(创建 AppConfig 实例) + 60.0 ms import lab/models.py + 60.3 ms LabConfig.ready() + 63.4 ms import proj/urls.py(ROOT_URLCONF) + 63.7 ms import lab/views.py + 68.0 ms import proj/mw.py
每个模块顶部都写了一行打点,记录被导入的时刻;AppConfig.__init__ 与 ready() 里同样打点。settings 是第一个出现的——它在第一次读取设置时才导入。接着 django.setup() 里按次序发生:导入 apps.py、创建 AppConfig 实例、导入 models、调用 ready()。urls、views、中间件模块在这条命令里晚一点才被导入(系统检查用到了它们)。
+ 0.0 ms import proj/settings.py(首次访问 settings 才会导入) + 10.3 ms import lab/apps.py(AppConfig 所在模块被导入) + 10.4 ms LabConfig.__init__(创建 AppConfig 实例) + 25.7 ms import lab/models.py + 26.0 ms LabConfig.ready() + 42.7 ms --- django.setup() 已完成 --- + 42.7 ms --- 发出第 1 个请求 --- + 42.9 ms import proj/mw.py + 43.0 ms MW.__init__(中间件链在首次请求前构建) + 43.1 ms MW.__call__ 进入 + 43.2 ms import proj/urls.py(ROOT_URLCONF) + 43.3 ms import lab/views.py + 43.4 ms view: hello() + 43.5 ms MW.__call__ 返回 + 43.6 ms --- 第 1 个请求结束 status=200 --- + 43.6 ms --- 发出第 2 个请求 --- + 43.8 ms MW.__call__ 进入 + 43.8 ms view: hello() + 43.8 ms MW.__call__ 返回 + 43.9 ms --- 第 2 个请求结束 ---
用 django.test.Client 在同一个进程里发两个请求。setup() 结束之后什么也没导入;第一个请求才导入中间件、ROOT_URLCONF、视图模块,并构建中间件链(MW.__init__);第二个请求只走 __call__ 和视图。所以「第一个请求比后面慢」的一部分就是这些模块的导入(用测试客户端量的,不等于真实服务器的首请求耗时)。
只有 contenttypes django.setup() 中位 102.8 ms contenttypes+auth+sessions+messages django.setup() 中位 121.2 ms 上面 + admin + staticfiles django.setup() 中位 128.8 ms
三种 INSTALLED_APPS 规模各在全新进程里 django.setup() 五次取中位数:数字随 app 增加缓慢增长。这个数字包含了导入 Django 自身模块的时间(manage.py 每个命令都要付一次),所以命令行工具启动慢主要是它。