Django包含已安装应用程序的注册表,这些应用程序存储配置并提供自省。它还维护一个可用的列表 models .
这个注册表被称为 apps 它在以下位置提供 django.apps :
>>> from django.apps import apps
>>> apps.get_app_config("admin").verbose_name
'Administration'
这一术语 project 描述了Django网络应用程序。项目Python包主要由设置模块定义,但它通常包含其他内容。例如,当你跑步时 django-admin startproject mysite 你会得到一个 mysite 包含 mysite Python包, settings.py , urls.py , asgi.py 和 wsgi.py .项目包通常会扩展为包括不绑定到特定应用程序的固定装置、CSS和模板等内容。
A 项目的根目录 (包含 manage.py )通常是一个项目的所有应用程序的容器,这些应用程序不是单独安装的。
术语 应用 描述一个提供一些特性的python包。应用 may be reused 在各种项目中。
应用程序包括一些模型、视图、模板、模板标记、静态文件、URL、中间件等的组合。它们通常与 INSTALLED_APPS 设置并可选使用其他机制,如urlconfs, MIDDLEWARE 设置或模板继承。
重要的是要理解Django应用程序是一组与框架各个部分交互的代码。根本没有所谓的 Application object.然而,Django需要在一些地方与已安装的应用程序交互,主要是为了配置,也是为了内省。这就是为什么应用程序注册中心在 AppConfig 每个已安装的应用程序的实例。
没有任何限制,项目包也不能被视为应用程序并具有模型等(这需要将其添加到 INSTALLED_APPS )
要配置应用程序,请创建 apps.py 模块,然后定义 AppConfig 那里
什么时候 INSTALLED_APPS 默认情况下,如果Django恰好找到一个应用程序模块,则包含应用程序模块的虚线路径 AppConfig 中的亚类 apps.py 子模块中,它将该配置用于应用程序。可以通过设置禁用此行为 AppConfig.default 至 False 。
如果 apps.py 模块包含多个 AppConfig 子类别,Django将寻找一个其中的一个 AppConfig.default 是 True 。
如果没有 AppConfig 发现了亚类,基 AppConfig 将使用类。
或者, INSTALLED_APPS 可能包含配置类的虚线路径以显式指定它::
INSTALLED_APPS = [
...,
"polls.apps.PollsAppConfig",
...,
]
如果你在一个叫做 anthology ,但是您希望它显示为“Jazz Manouche”,您可以提供自己的配置:
# anthology/apps.py
from rock_n_roll.apps import RockNRollConfig
class JazzManoucheConfig(RockNRollConfig):
verbose_name = "Jazz Manouche"
# anthology/settings.py
INSTALLED_APPS = [
"anthology.apps.JazzManoucheConfig",
# ...
]
此示例显示位于名为 apps.py .这是一个惯例,而不是要求。 AppConfig 子类可以在任何地方定义。
在这种情况下, INSTALLED_APPS 必须包含配置类的虚线路径,因为它位于应用程序外部,因此无法自动检测到。
应用程序的完整python路径,例如 'django.contrib.admin' .
此属性定义配置应用于哪个应用程序。必须全部设置 AppConfig 子类。
它在Django项目中必须是独一无二的。
应用程序的简称,例如 'admin'
此属性允许在两个应用程序具有冲突标签时重新标记应用程序。它默认为的最后一个组件 name . 它应该是有效的python标识符。
它在Django项目中必须是独一无二的。
警告
在应用程序应用迁移后更改此属性将导致对项目的更改中断,或者(对于可重复使用的应用程序)该应用程序的任何现有安装的更改中断。这是因为 AppConfig.label 当引用依赖项列表中的应用程序时,在数据库表和迁移文件中使用。
应用程序的可读名称,例如“管理”。
此属性默认为 label.title() .
应用程序目录的文件系统路径,例如 '/usr/lib/pythonX.Y/dist-packages/django/contrib/admin' .
在大多数情况下,Django可以自动检测和设置该属性,但您也可以在 AppConfig 子类。在一些情况下,这是必需的;例如,如果应用程序包是 namespace package 有多条路径。
将此属性设置为 False 防止Django自动选择配置类。这在以下情况下很有用 apps.py 只界定一条 AppConfig 子类别,但您不希望Django默认使用它。
将此属性设置为 True 告诉Django自动选择配置类。这在以下情况下很有用 apps.py 限定多于一个 AppConfig 子类,您希望Django默认使用其中之一。
默认情况下,不设置此属性。
要添加到此应用程序中的模型的隐式公钥类型。您可以使用它来保留 AutoField 作为第三方应用程序的主密钥类型。
默认情况下,这是 DEFAULT_AUTO_FIELD 。
应用程序的根模块,例如 <module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'> .
包含模型的模块,例如 <module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'> .
它可能是 None 如果应用程序不包含 models 模块。注意与数据库相关的信号,如 pre_migrate 和 post_migrate 仅对具有 models 模块。
返回的iterable Model 此应用程序的类。
需要完全填充应用程序注册表。
返回 Model 用给定的 model_name . model_name 不区分大小写。
加薪 LookupError 如果此应用程序中不存在此类模型。
需要完全填充应用程序注册表,除非 require_ready 参数设置为 False . require_ready 行为与 apps.get_model() .
子类可以重写此方法以执行初始化任务,如注册信号。一旦注册表完全填充,就调用它。
虽然您不能在模块级导入模型,但是 AppConfig 类已定义,可以将它们导入 ready() ,使用 import 语句或 get_model() .
如果你在注册 model signals ,您可以通过其字符串标签引用发送者,而不是使用模型类本身。
例子::
from django.apps import AppConfig
from django.db.models.signals import pre_save
class RockNRollConfig(AppConfig):
# ...
def ready(self):
# importing model classes
from .models import MyModel # or...
MyModel = self.get_model("MyModel")
# registering signals with the model's string label
pre_save.connect(receiver, sender="app_label.MyModel")
警告
尽管您可以访问上面描述的模型类,但请避免与您的 ready() 实施。这包括执行查询的模型方法 (save() , delete() ,管理器方法等),以及通过 django.db.connection . 你的 ready() 方法将在每个管理命令的启动过程中运行。例如,即使测试数据库配置与生产设置分开, manage.py test 仍然会对您的 生产 数据库!
备注
在通常的初始化过程中, ready 方法只被Django调用一次。但在一些特殊情况下,特别是在摆弄安装的应用程序的测试中, ready 可能会被多次调用。在这种情况下,要么编写幂等方法,要么在 AppConfig 类来防止重新运行应该只执行一次的代码。
没有 __init__.py 文件被称为“名称空间包”,可以分布在多个目录中的不同位置 sys.path (见 PEP 420 )
Django应用程序需要一个单一的基本文件系统路径,其中Django(取决于配置)将搜索模板、静态资产等。因此,只有在以下情况之一为真时,命名空间包才可能是Django应用程序:
如果这两个条件都不满足,Django将提高 ImproperlyConfigured .
应用程序注册表提供以下公共API。以下未列出的方法被视为私有方法,可能会更改,恕不另行通知。
设置为的布尔属性 True 在注册表完全填充之后 AppConfig.ready() 方法被调用。
返回一个 AppConfig 对于给定的应用程序 app_label . 加薪 LookupError 如果不存在此类应用程序。
检查注册表中是否存在具有给定名称的应用程序。 app_name 是应用程序的全名,例如 'django.contrib.admin' .
返回 Model 用给定的 app_label 和 model_name . 作为快捷方式,此方法还接受表单中的单个参数 app_label.model_name . model_name 不区分大小写。
加薪 LookupError 如果不存在此类应用程序或模型。加薪 ValueError 当用不包含一个点的单个参数调用时。
需要完全填充应用程序注册表,除非 require_ready 参数设置为 False .
设置 require_ready 到 False 允许查找模型 while the app registry is being populated 特别是在导入模型的第二个阶段。然后 get_model() 与导入模型的效果相同。主要的用例是使用设置配置模型类,例如 AUTH_USER_MODEL .
什么时候? require_ready 是 False , get_model() 返回在应用程序注册表完全填充之前可能无法完全正常工作的模型类(例如,反向访问器可能丢失)。因此,最好离开 require_ready 默认值为 True 只要可能。
当Django开始的时候, django.setup() 负责填充应用程序注册表。
通过以下方式配置Django:
正在加载设置。
正在设置日志记录。
如果 set_prefix 为true,将URL冲突解决程序脚本前缀设置为 FORCE_SCRIPT_NAME 如果定义,或 / 否则。
正在初始化应用程序注册表。
此函数自动调用:
当通过Django的ASGI或WSGI支持运行HTTP服务器时。
调用管理命令时。
在其他情况下必须显式调用它,例如在纯Python脚本中。
应用程序注册表分三个阶段初始化。在每个阶段,Django按照以下顺序处理所有应用程序: INSTALLED_APPS .
第一个django导入 INSTALLED_APPS .
如果是应用程序配置类,Django将导入应用程序的根包,由其 name 属性如果是Python包,Django会在 apps.py 子模块,否则创建默认应用程序配置。
在这个阶段,您的代码不应该导入任何模型!
换句话说,应用程序的根包和定义应用程序配置类的模块不应该导入任何模型,甚至是间接导入。
严格来说,Django允许在加载应用程序配置后导入模型。但是,为了避免不必要的限制 INSTALLED_APPS ,强烈建议在此阶段不要导入任何模型。
完成此阶段后,在应用程序配置(如 get_app_config() 变得有用。
然后Django尝试导入 models 每个应用程序的子模块(如果有)。
必须定义或导入应用程序中的所有模型 models.py 或 models/__init__.py . 否则,此时可能无法完全填充应用程序注册表,这可能导致ORM故障。
一旦这个阶段完成,在诸如 get_model() 变得有用。
最后Django运行了 ready() 每个应用程序配置的方法。
以下是初始化过程中可能遇到的一些常见问题:
AppRegistryNotReady :当导入应用程序配置或模型模块触发依赖于应用程序注册表的代码时,会发生这种情况。
例如, gettext() 使用应用程序注册表在应用程序中查找翻译目录。要在导入时翻译,您需要 gettext_lazy() 相反。(使用) gettext() 这将是一个错误,因为转换将在导入时发生,而不是在每个请求时发生,具体取决于活动语言。)
在模型模块中导入时使用ORM执行数据库查询也将触发此异常。在所有模型都可用之前,ORM无法正常工作。
如果忘记调用 django.setup() 在独立的python脚本中。
ImportError: cannot import name ... 如果导入序列以循环结束,就会发生这种情况。
为了消除这些问题,您应该最小化模型模块之间的依赖关系,并且在导入时尽可能少地进行工作。为了避免在导入时执行代码,可以将代码移到函数中并缓存其结果。当您第一次需要它的结果时,代码将被执行。这个概念被称为“懒惰的评估”。
django.contrib.admin 自动执行自动发现 admin 已安装应用程序中的模块。为了防止它,改变你的 INSTALLED_APPS 遏制 'django.contrib.admin.apps.SimpleAdminConfig' 而不是 'django.contrib.admin' .
RuntimeWarning: Accessing the database during app initialization is discouraged. 在应用程序准备就绪之前执行的数据库查询会触发此警告,例如在模块导入期间或在 AppConfig.ready() 方法。不鼓励这种过早的数据库查询,因为它们将在每个管理命令启动时运行,这将减慢您的项目启动速度,可能会缓存过时的数据,如果迁移挂起,甚至可能失败。
例如,进行数据库查询以填充表单域选项是一个常见的错误:
class LocationForm(forms.Form):
country = forms.ChoiceField(choices=[c.name for c in Country.objects.all()])
在上面的示例中,来自 Country.objects.all() 在模块导入期间执行,因为 QuerySet 都被迭代了。若要避免该警告,该窗体可以使用 ModelChoiceField 相反::
class LocationForm(forms.Form):
country = forms.ModelChoiceField(queryset=Country.objects.all())
为了更容易找到触发此警告的代码,您可以将 treat warnings as errors 要显示堆栈跟踪,请执行以下操作 python -Werror manage.py shell 。
5月 28, 2025