AppConfig.ready() 是 Django 唯一安全可靠的初始化入口,它在所有模型注册完成、信号系统就绪后调用;不能在 __init__.py 或 models.py 中初始化,否则易因导入顺序导致模型未就绪、信号失效等问题。

AppConfig 是 Django 中唯一被框架原生支持、在应用生命周期早期介入且能可靠触发的配置入口。它不是“推荐方式”,而是唯一能安全执行初始化逻辑的位置——其他地方(比如 models.py 导入时、<strong>init</strong>.py 里)都可能因导入顺序或懒加载机制导致信号未注册、缓存未初始化、模型未就绪等问题。
为什么不能在 __init__.py 或 models.py 里初始化?
因为 Django 的应用注册和模型加载是分阶段进行的:apps.py 中的 AppConfig.ready() 方法会在所有模型类定义完成、数据库连接可用、信号系统就绪后才被调用。而 __init__.py 在模块首次导入时就执行,此时 models 可能还没被 import;models.py 被导入时,django.apps.apps 注册表甚至可能还未完成扫描。
-
ready()是唯一保证模型已注册、apps.get_model()可用的钩子 - 在
ready()外连接post_save等信号,大概率失效(信号接收器找不到 sender 或被跳过) - Django 2.0+ 已明确文档警告:禁止在
ready()之外做模型级操作
INSTALLED_APPS 中写 'myapp' 和 'myapp.apps.MyAppConfig' 的区别
写 'myapp' 是让 Django 自动查找 myapp/apps.py 中的默认 AppConfig 子类(前提是该子类设置了 default = True 或是唯一子类);写 'myapp.apps.MyAppConfig' 是显式指定配置类,绕过自动发现逻辑。
- 如果
myapp/apps.py里有多个AppConfig子类,Django 不会猜——必须显式指定路径,否则报错django.core.exceptions.ImproperlyConfigured: Application labels aren't unique - 如果只写
'myapp'但apps.py里没定义任何AppConfig子类,Django 会回退到基类AppConfig,此时ready()不会被调用(基类的ready()是空实现) -
default_app_config在myapp/__init__.py中已弃用(Django 3.2+ 警告,4.0+ 移除),必须改用INSTALLED_APPS显式路径
AppConfig.ready() 里能做什么、不能做什么
它适合做“一次性启动任务”,但不是万能初始化入口。关键限制在于:不能触发数据库写操作(如 Model.objects.create()),也不能依赖尚未 ready 的其他应用。
立即学习“Python免费学习笔记(深入)”;
- ✅ 安全:连接信号(
post_save.connect(...))、注册自定义管理命令、预热缓存键、设置全局变量 - ⚠️ 风险:调用
apps.get_app_config("otherapp")—— 如果otherapp在INSTALLED_APPS中排在后面,它可能还没ready() - ❌ 禁止:执行数据库写、访问未 migrate 的表、在
ready()里再 import 当前 app 的models(容易循环导入)
自定义属性(如 version)怎么被其他代码访问?
不能靠实例属性直接读取——AppConfig 实例由 django.apps.apps 统一管理,你需要从注册表中获取:
from django.apps import apps
config = apps.get_app_config("myapp")
print(config.version) # 前提是 MyAppConfig 类里定义了 version = "1.0.1"
- 这个
config对象是单例,整个生命周期内唯一 - 不要在
ready()外部通过MyAppConfig()手动实例化——那只是个新对象,和 Django 管理的实例无关 - 如果想让配置更易用,可封装成模块级函数,内部调用
apps.get_app_config()
真正容易被忽略的是:Django 的应用注册顺序决定了 ready() 的调用顺序,而这个顺序完全由 INSTALLED_APPS 列表顺序决定。如果你的应用依赖另一个应用的初始化结果,就必须确保它在列表中排在后者之后——这点没有错误提示,只会静默失败。


















