应用¶ T0>

Django包含已安装应用程序的注册表,用于存储配置并提供反思。 它还保留了可用models的列表。

这个注册表简称为apps,它可以在django.apps中找到:

>>> from django.apps import apps
>>> apps.get_app_config('admin').verbose_name
'Admin'

项目和应用程序

术语项目描述了一个Django web应用程序。 项目Python包主要由设置模块定义,但通常包含其他内容。 For example, when you run django-admin startproject mysite you’ll get a mysite project directory that contains a mysite Python package with settings.py, urls.py, and wsgi.py. 项目包通常被扩展为包括固件,CSS和不与特定应用程序绑定的模板。

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

术语application描述了提供一些特征的Python包。 应用程序may be reused

应用程序包括模型,视图,模板,模板标签,静态文件,URL,中间件等的一些组合。它们通常通过INSTALLED_APPS设置连接到项目中,并且可以与其他机制(如URLconf, MIDDLEWARE设置或模板继承。

理解Django应用程序只是一组与框架各个部分交互的代码是非常重要的。 没有像Application对象那样的东西。 然而,Django需要与已安装的应用程序进行交互,这主要是为了配置和内省。 这就是为什么应用程序注册表在每个已安装的应用程序的AppConfig实例中维护元数据的原因。

没有限制,一个项目包不能被视为一个应用程序,并有模型等(这将需要添加到INSTALLED_APPS)。

配置应用程序

要配置一个应用程序,请在INSTALLED_APPS子目录AppConfig中加入该子类的虚线路径。

INSTALLED_APPS仅包含应用程序模块的虚线路径时,Django将在该模块中检查default_app_config变量。

如果已经定义,则是该应用程序的AppConfig子类的虚线路径。

如果没有default_app_config,Django使用基本的AppConfig类。

default_app_config允许Django 1.7之前的应用程序(如django.contrib.admin)选择AppConfig功能,而不需要用户更新INSTALLED_APPS

新的应用程序应该避免default_app_config 相反,他们应该要求在INSTALLED_APPS中明确配置合适的AppConfig子类的虚线路径。

对于应用程序作者

如果您正在创建一个名为“Rock”'Roll'的可插入应用程序,请按照以下步骤为管理员提供适当的名称:

# rock_n_roll/apps.py

from django.apps import AppConfig

class RockNRollConfig(AppConfig):
    name = 'rock_n_roll'
    verbose_name = "Rock ’n’ roll"

你可以使你的应用程序默认加载这个AppConfig子类,如下所示:

# rock_n_roll/__init__.py

default_app_config = 'rock_n_roll.apps.RockNRollConfig'

INSTALLED_APPS只包含'rock_n_roll'时,会导致使用RockNRollConfig 这允许您使用AppConfig功能,而无需用户更新其INSTALLED_APPS设置。 除了这个用例之外,最好避免使用default_app_config,而是在INSTALLED_APPS中指定应用配置类,如下所述。

当然,您也可以告诉您的用户在INSTALLED_APPS设置中放置'rock_n_roll.apps.RockNRollConfig' 您甚至可以提供具有不同行为的几个不同的AppConfig子类,并允许用户通过它们的INSTALLED_APPS设置选择一个子类。

推荐的约定是将配置类放在名为apps的应用程序的子模块中。 但是,这不是由Django强制执行的。

您必须包含Django的name属性以确定此配置适用于哪个应用程序。 您可以定义AppConfig API参考中记录的任何属性。

注意

如果您的代码在应用程序的__init__.py中导入应用程序注册表,apps名称将与apps子模块冲突。 最佳做法是将该代码移到子模块并导入。 解决方法是以不同的名称导入注册表:

from django.apps import apps as django_apps

对于应用程序用户

如果您在名为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的子模块中定义项目特定的配置类是一个约定,而不是要求。

应用程序配置

AppConfig[source]

应用程序配置对象存储应用程序的元数据 一些属性可以在AppConfig子类中配置。 其他的由Django设置,只读。

可配置的属性

AppConfig中。名称 T0> ¶ T1>

完整的Python路径到应用程序,例如'django.contrib.admin'

该属性定义配置适用于哪个应用程序。 它必须在所有的AppConfig子类中设置。

它在Django项目中必须是唯一的。

AppConfig中。标签 T0> ¶ T1>

应用程序的简称,例如'admin'

当两个应用程序有冲突的标签时,该属性允许重新标记应用程序。 它默认为name的最后一个组件。 它应该是一个有效的Python标识符。

它在Django项目中必须是唯一的。

AppConfig中。 verbose_name T0> ¶ T1>

人类可读的应用程序名称,例如“行政”。

该属性默认为label.title()

AppConfig中。路径 T0> ¶ T1>

到应用程序目录的文件系统路径,例如'/usr/lib/python3.4/dist-packages/django/contrib/admin'

在大多数情况下,Django可以自动检测并设置它,但是您也可以在您的AppConfig子类上提供一个显式覆盖作为类属性。 在少数情况下,这是必需的;例如,如果应用程序包是一个包含多个路径的名称空间包

只读属性

AppConfig中。模块 T0> ¶ T1>

Root module for the application, e.g. <module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'>.

AppConfig中。 models_module T0> ¶ T1>

Module containing the models, e.g. <module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'>.

如果应用程序不包含models模块,则可能是None Note that the database related signals such as pre_migrate and post_migrate are only emitted for applications that have a models module.

方法¶ T0>

AppConfig中。get_models()[source]

返回此应用程序的Model类的迭代。

需要应用程序注册表完全填充。

AppConfig中。get_modelmodel_namerequire_ready = True[source]

用给定的model_name返回Model model_name is case-insensitive.

如果此应用程序中不存在此类模型,则引发LookupError

除非将require_ready参数设置为False,否则需要将应用程序注册表完全填充。 require_ready的行为与apps.get_model()中的行为完全相同。

Django 1.11新增功能:

添加了require_ready关键字参数。

AppConfig中。ready()[source]

子类可以覆盖此方法来执行初始化任务,如注册信号。 只要注册表完全填充,就会被调用。

Although you can’t import models at the module-level where AppConfig classes are defined, you can import them in ready(), using either an import statement or get_model().

如果你正在注册model signals,你可以通过它的字符串标签来引用发送者,而不是使用模型类本身。

例:

from django.db.models.signals import pre_save

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类上放一个标志,以防止重新运行一次应该执行的代码。

名称空间包作为应用程序

Python packages without an __init__.py file are known as “namespace packages” and may be spread across multiple directories at different locations on sys.path (see PEP 420).

Django应用程序需要一个基本的文件系统路径,其中Django(取决于配置)将搜索模板,静态资产等。 因此,如果满足以下条件之一,名称空间包只能是Django应用程序:

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

如果这两个条件都不满足,Django将会引发ImproperlyConfigured

应用程序注册表

应用 T0> ¶ T1>

应用程序注册表提供以下公共API。 以下未列出的方法被认为是私密的,可能会在没有通知的情况下更改

应用。就绪 T0> ¶ T1>

在注册表完全填充并调用所有AppConfig.ready()方法后,设置为True的布尔属性。

应用。 get_app_configs T0>()¶ T1>

返回一个AppConfig实例的迭代。

应用。 get_app_config T0>( app_label T1>)¶ T2>

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

应用。 is_installed T0>( APP_NAME T1>)¶ T2>

检查具有给定名称的应用程序是否存在于注册表中。 app_name is the full name of the app, e.g. 'django.contrib.admin'.

应用。get_modelapp_labelmodel_namerequire_ready = True

用给定的app_labelmodel_name返回Model 作为一个快捷方式,这个方法也以app_label.model_name的形式接受一个参数。 model_name is case-insensitive.

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

除非将require_ready参数设置为False,否则需要将应用程序注册表完全填充。

Setting require_ready to False allows looking up models while the app registry is being populated, specifically during the second phase where it imports models. 那么get_model()与导入模型具有相同的效果。 主要的用例是使用设置来配置模型类,比如AUTH_USER_MODEL

When require_ready is False, get_model() returns a model class that may not be fully functional (reverse accessors may be missing, for example) until the app registry is fully populated. 因此,尽可能将require_ready保留为True的默认值。

Django 1.11新增功能:

添加了require_ready关键字参数。

初始化过程

如何加载应用程序

When Django starts, django.setup() is responsible for populating the application registry.

setup(set_prefix=True)[source]

通过以下方式配置Django:

  • 加载设置。
  • 设置日志记录。
  • 如果set_prefix为True,则将URL解析器脚本前缀设置为FORCE_SCRIPT_NAME,否则设置为/
  • 初始化应用程序注册表。

这个功能是自动调用的:

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

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

应用程序注册表分三个阶段初始化。 在每个阶段,Django按照INSTALLED_APPS的顺序处理所有的应用程序。

  1. 首先Django在INSTALLED_APPS中导入每个项目。

    如果它是一个应用程序配置类,Django将导入由其name属性定义的应用程序的根包。 如果它是一个Python包,Django将创建一个默认的应用程序配置。

    在这个阶段,你的代码不应该导入任何模型!

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

    严格来说,Django允许在加载应用程序配置后导入模型。 但是,为了避免对INSTALLED_APPS顺序的不必要的约束,强烈建议不要在此阶段导入任何模型。

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

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

    您必须在应用程序的models.pymodels/__init__.py中定义或导入所有模型。 否则,此时应用程序注册表可能不会完全填充,这可能会导致ORM出现故障。

    一旦这个阶段完成,在诸如get_model()的模型上运行的API就变得可用。

  3. 最后,Django运行每个应用程序配置的ready()方法。

故障排除¶ T0>

以下是在初始化过程中可能遇到的一些常见问题:

  • AppRegistryNotReady: This happens when importing an application configuration or a models module triggers code that depends on the app registry.

    例如,gettext()使用应用程序注册表在应用程序中查找翻译目录。 要在导入时翻译,您需要gettext_lazy() (使用gettext()会是一个错误,因为翻译将在导入时发生,而不是在每个请求(取决于活动语言)。

    在模型模块中导入时使用ORM执行数据库查询也会触发此异常。 直到所有型号都可用,ORM才能正常运行。

    如果忘记在独立的Python脚本中调用django.setup(),也会发生此异常。

  • 导入错误: 不能 进口 名称 ... 如果导入序列以循环结束,则会发生这种情况。

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

  • django.contrib.admin automatically performs autodiscovery of admin modules in installed applications. 为了防止这种情况发生,请将您的INSTALLED_APPS更改为包含'django.contrib.admin.apps.SimpleAdminConfig'而不是'django.contrib.admin'