应用程序

    这个注册表叫做 ,它在 django.app 中可用:

    术语 项目 描述了一个 Django 网络应用。项目的 Python 包主要是由一个配置模块定义的,但它通常包含其他东西。例如,当你运行 django-admin startproject mysite 时,你会得到一个 mysite 项目目录,其中包含一个 mysite 的 Python 包,其中有 settings.pyurls.pyasgi.pywsgi.py。该项目包经常被扩展到包括像辅助工具、CSS 和模板这样的东西,这些东西并不与特定的应用程序相关。

    一个 项目的根目录 (包含 manage.py 文件的目录)通常是项目中所有未单独安装的应用程序的容器。

    术语 应用程序 指的是提供了一些功能的 Python 包。应用程序 。

    应用程序包括模型,视图,模板,模板标签,静态文件,URL,中间件等的一些组合。它们通常使用 INSTALLED_APPS 选项加入到项目中,也可以使用其他机制,如 URLconf, 配置或模板继承。

    重要的是要理解 Django 应用程序是一组与框架各部分交互的代码。并不存在 Application 对象这种东西。但是,在一些地方,Django 需要与已安装的应用进行交互,主要是为了配置,也是为了自省。所以应用注册表为每个安装的应用在一个 AppConfig 实例中维护元数据。

    一个项目包可以自由的作为一个应用程序并包含一些模型等(前提是,需要把它加入 )。

    To configure an application, create an apps.py module inside the application, then define a subclass of AppConfig there.

    When contains the dotted path to an application module, by default, if Django finds exactly one AppConfig subclass in the apps.py submodule, it uses that configuration for the application. This behavior may be disabled by setting to False.

    If the apps.py module contains more than one AppConfig subclass, Django will look for a single one where is True.

    If no AppConfig subclass is found, the base class will be used.

    Alternatively, INSTALLED_APPS may contain the dotted path to a configuration class to specify it explicitly:

    1. INSTALLED_APPS = [
    2. ...
    3. ...
    4. ]

    如果你正在创建一个名为 “Rock ’n’ roll” 的可插拔应用,那么这边将告诉你将如何为管理后台提供一个合适的名称:

    RockNRollConfig will be loaded automatically when contains 'rock_n_roll'. If you need to prevent this, set default to False in the class definition.

    You can provide several subclasses with different behaviors. To tell Django which one to use by default, set default to True in its definition. If your users want to pick a non-default configuration, they must replace 'rock_n_roll' with the dotted path to that specific class in their setting.

    The AppConfig.name attribute tells Django which application this configuration applies to. You can define any other attribute documented in the API reference.

    AppConfig subclasses may be defined anywhere. The apps.py convention merely allows Django to load them automatically when contains the path to an application module rather than the path to a configuration class.

    注解

    若你在应用的 __init__.py 中导入了应用注册信息,名称 apps 会与子模块 apps 冲突。最好的办法是将此段带入移入子模块,再导入它。折中方案是导入后取个别名:

    1. from django.apps import apps as django_apps

    Changed in Django Development version:

    In previous versions, a default_app_config variable in the application module was used to identify the default application configuration class.

    对于应用程序使用者

    项目中直接使用 “Rock ’n’ roll”,其名字会是 anthology,但是你可能期望显示 “Jazz Manouche”,这需要你提供自定义配置:

    This example shows project-specific configuration classes located in a submodule called apps.py. This is a convention, not a requirement. AppConfig subclasses may be defined anywhere.

    In this situation, must contain the dotted path to the configuration class because it lives outside of an application and thus cannot be automatically detected.

    class AppConfig

    应用程序配置对象存储了应用的元数据。某些属性可以在 AppConfig 的子类中配置。而其它 Django 设置好的配置是只读的。

    AppConfig.``name

    指向此应用程序的完整的 Python 格式的路径,如 'django.contrib.admin'

    此属性定义配置适用的应用程序。每个 子类都必须包含此项。

    它必须在整个 Django 项目中唯一。

    AppConfig.``label

    应用程序简称,如

    此属性允许在两个应用标签冲突时重命名其中一个的标签名。默认是 name 的最后一段。必须是一个有效的 Python 标识符。

    它必须在整个 Django 项目中唯一。

    AppConfig.``verbose_name

    应用程序容易被人理解的名称,如 “Administration”。

    此属性默认值为 label.title()

    应用目录的文件系统路径,如 '/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'

    大多数情况下,Django 能自动检测并设置此属性,但你也能在 AppConfig 子类中申明此属性,显式地重写它。很少情况下要这么做;例如,若应用包是一个拥有多个路径的 。

    AppConfig.``default

    New in Django Development version.

    Set this attribute to False to prevent Django from selecting a configuration class automatically. This is useful when apps.py defines only one AppConfig subclass but you don’t want Django to use it by default.

    Set this attribute to True to tell Django to select a configuration class automatically. This is useful when apps.py defines more than one subclass and you want Django to use one of them by default.

    By default, this attribute isn’t set.

    AppConfig.``default_auto_field

    New in Django Development version.

    The implicit primary key type to add to models within this app. You can use this to keep AutoField as the primary key type for third party applications.

    By default, this is the value of .

    只读属性

    AppConfig.``module

    应用程序的根模块,如 <module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'>

    AppConfig.``models_module

    包含模型的模块,如 <module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'>

    应用不包含 models 模块时,可能是 None。注意,数据库关联的信号,例如 pre_migrate 和 仅在应用有 models 模块时发出。

    AppConfig.``get_models()

    为该应用返回一个可迭代的 Model 类。

    要求完整填写应用注册表。

    AppConfig.``get_model(model_name, require_ready=True)

    返回给出的 model_name 的 。 model_name 是大小写敏感的。

    如果应用程序中不存在此模块,则抛出 LookupError 异常。

    require_ready 参数为 False 的情况下,都必须完整设置注册信息。 require_ready 行为与 一致。

    AppConfig.``ready()

    子类可以重写此方法来执行类似注册信号的初始化任务。只要注册表被填满就会调用此方法。

    虽然你不能在定义 AppConfig 类的模型层导入模型,但可以在 ready() 中导入,通过 import 语句或 。

    若你正在注册 model signals,你可以通过字符串标签追踪发信者,而不是用模型类。

    举例:

    1. from django.apps import AppConfig
    2. from django.db.models.signals import pre_save
    3. class RockNRollConfig(AppConfig):
    4. # ...
    5. def ready(self):
    6. # importing model classes
    7. from .models import MyModel # or...
    8. MyModel = self.get_model('MyModel')
    9. pre_save.connect(receiver, sender='app_label.MyModel')

    警告

    尽管可以向上面介绍的那样访问模型类,但是要避免在 实现中与数据库交互。这包括了那些会通过 django.db.connection 执行查询 (save(), ,管理器方法,等等)和原生查询的模型方法。你的 ready() 方法会在每个管理命令初始化阶段被执行。例如,虽然测试数据库的配置与生成环境配置是分开的, manager.py test 仍会对 生产环境 数据库执行一些查询操作。

    注解

    在普通的初始化进程中, ready 方法仅被 Django 调用一次。但在一些特殊情况下,特别是针对已安装应用的测试中,可以会多次调用 。这种情况下,在 AppConfig 类中编写幂等方法或放入一个标志,避免那些只需运行一次的代码被多次执行。

    命名空间包作为应用程序

    没有 __init__.py 文件的 Python 包被称为 “命名空间包”,可以分布在 sys.path 上不同位置的多个目录中(见 )。

    Django 应用程序需要一个单一的基础文件系统路径,Django(取决于配置)将在其中搜索模板、静态资产等。因此,只有在以下情况之一为真时,命名空间包才可能是 Django 应用程序:

    1. 名称空间包实际上只有一个位置(即不分布在多个目录中)。
    2. 用于配置应用的 AppConfig 类有一个 类属性,它是 Django 将作为应用的单一基础路径的绝对目录路径。

    如果这些条件均不满足的话,Django 将抛出 ImproperlyConfigured 错误。

    apps

    应用程序注册表提供以下公共 API。以下未列出的方法被视为私有方法,可能会更改,恕不另行通知。

    在注册表完全填充和调用所有 方法后设置为 True 的布尔属性。

    apps.``get_app_configs()

    返回一个由 AppConfig 实例组成的可迭代对象

    apps.``get_app_config(app_label)

    返回给定 app_label 的应用程序的 。如果不存在这样的应用程序,则会引发 LookupError

    apps.``is_installed(app_name)

    检查注册表中是否存在给定名称的应用程序。app_name 是应用程序的全名,例如 'django.contrib.admin'

    apps.``get_model(app_label, model_name, require_ready=True)

    返回 于给定的 app_labelmodel_name。作为快捷方式,本方法也接受一个单一参数,形式为 app_label.model_name. model_name 不区分大小写。

    如果不存在这样的应用程序或模型,则引发 LookupError。当调用的单个参数不包含一个点时,会引发 。

    除非 require_ready 参数设置为 False,否则要求应用注册表被完全填充。

    require_ready 设置为 False 允许 在应用注册表被填充 的时候,特别是在导入模型的第二阶段,查找模型。那么 get_model() 就和导入模型的效果一样。主要用例是用设置配置模型类,如 。

    require_readyFalse 时,get_model() 返回的模型类可能无法完全发挥作用(例如,可能缺少反向访问器),直到应用程序注册表完全填充。因此,最好尽可能将 require_ready 改为默认值 True

    Django 启动后, django.setup() 负责配置应用注册信息。

    setup(set_prefix=True)

    配置 Django:

    • 加载配置。
    • 设置日志。
    • set_prefix 为 True,为 URL 处理器脚本增加前缀 FORCE_SCRIPT_NAME,若未定义此项,则使用 /
    • 初始化应用程序注册。

    这个函数会被自动调用:

    • 当通过 Django 的 WSGI 支持运行 HTTP 服务。
    • 调用一个管理命令时。

    在其他情况下,必须显式调用它,例如在纯 Python 脚本中。

    应用注册的初始化过程分三个阶段完成。在每个阶段,Django 根据应用在 中的顺序依次处理。

    1. 首先,Django 导入 INSTALLED_APPS 中各项条目。

      If it’s an application configuration class, Django imports the root package of the application, defined by its attribute. If it’s a Python package, Django looks for an application configuration in an apps.py submodule, or else creates a default application configuration.

      在这情况下,你的代码不应该导入任何模型!

      换句话说,应用程序的根包和定义应用程序配置类的模块不能导入任何模型,即使是间接导入。

      严格来说,一旦应用配置完成加载后,Django 是允许导入模型。然而为了避免不必要的 INSTALLED_APPS, 顺序约束。强烈建议在这个阶段不要导入任何模型。

      一旦这个阶段完成,可以使用 API 对应用程序配置(如 )进行操作。

    2. 然后 Django 会尝试导入每个应用程序的 models 子模块,如果有的话。

      你必须在你的应用程序的 models.pymodels/__init__.py 中定义或导入所有模型。否则,应用程序注册表可能在此时没有完全填充,这可能导致 ORM 失灵。

      此步骤完成后,操作模型的 API,例如 get_model(),就可以使用了。

    3. 最后 Django 会运行每个应用配置的 方法。

    错误调试

    在初始化期间,这里有一些常见的错误你可能会遇上。

    • AppRegistryNotReady。当导入应用程序配置或模型模块触发依赖于应用程序注册表的代码时,会发生这种情况。

      例如, 使用应用程序注册表来查找应用程序中的翻译目录。要在导入时进行翻译,你需要 gettext_lazy() 来代替。(使用 会是一个 bug,因为翻译会在导入时进行,而不是在每次请求时根据活动语言进行。)

      在模型模块中导入时用 ORM 执行数据库查询也会触发此异常。在所有模型都可用之前,ORM 无法正常工作。

      如果你忘记在一个单独的 Python 脚本中调用函数 django.setup(),也会发生异常。

    • ImportError: cannot import name ... 如果导入序列陷入循环,就会发生这种情况。

      为了消除这些问题,你应该最大限度地减少模型模块之间的依赖关系,并在导入时尽可能减少复杂度。 为了避免在导入时执行代码,可以将其移入函数并缓存结果。 代码将在你首次需要结果时执行。 这个概念被称为“惰性求值”。

    • django.contrib.admin 会自动在已安装的应用程序中执行 admin 模块的自动发现。为了防止这种情况发生,请将你的 INSTALLED_APPS 改为包含 'django.contrib.admin.app.SimpleAdminConfig' 而不是 。