“Django/docs/3.0.x/ref/applications”的版本间差异

来自菜鸟教程
Django/docs/3.0.x/ref/applications
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:应用程序 — Django 文档}}
 
<div id="module-django.apps" class="section">
 
<div id="module-django.apps" class="section">
  
第4行: 第5行:
 
= 应用 =
 
= 应用 =
  
Django 包含一个已安装应用配置记录,能够存储配置和内省。它同时还维护一个可用的 [[../../topics/db/models|<span class="doc">模型</span>]] 列表。
+
Django 包含一个已安装应用程序的注册表,用于存储配置并提供自省。 它还维护一个可用 [[../../topics/db/models|模型]] 的列表。
  
此注册表称为:attr:应用`~django.apps.apps` ,并且它可用于:mod:django.apps::。
+
此注册表称为 [[#django.apps.apps|apps]],它在 [[#module-django.apps|django.apps]] 中可用:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第12行: 第13行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.apps import apps
+
<syntaxhighlight lang="python">>>> from django.apps import apps
&gt;&gt;&gt; apps.get_app_config('admin').verbose_name
+
>>> apps.get_app_config('admin').verbose_name
'Administration'</pre>
+
'Administration'</syntaxhighlight>
  
 
</div>
 
</div>
第23行: 第24行:
 
== 项目和应用 ==
 
== 项目和应用 ==
  
术语 '''project(项目)''' 指的是一个 Django web 应用,该项目的Python包主要包含配置模块,但通常也包含其他内容。例如,当你在命令行执行 <code>django-admin startproject mysite</code> 命令时,你会得到一个名为 <code>mysite</code>  的项目目录,其中包含一个同样名为 <code>mysite</code> 的Python包,Python包内包括 <code>settings.py</code>、 <code>urls.py</code><code>asgi.py</code> 和 [[#id1|<span id="id2" class="problematic">``</span>]]wsgi.py``等文件。项目的Python包通常也会扩展从而包含一些其他内容,比如fixture、CSS,以及与特定应用绑定的模板等。
+
术语 '''project''' 描述了 Django Web 应用程序。 项目 Python 包主要由设置模块定义,但它通常包含其他内容。 例如,当您运行 <code>django-admin startproject mysite</code> 时,您将获得一个 <code>mysite</code> 项目目录,其中包含一个 <code>mysite</code> Python 包,其中包含 <code>settings.py</code>、<code>urls.py</code> , <code>asgi.py</code> 和 <code>wsgi.py</code>。 项目包通常会扩展为包含不绑定到特定应用程序的夹具、CSS 和模板等内容。
  
一个 '''项目的根目录''' (包含 <code>manage.py</code> 文件的目录) 通常是所有项目应用程序的容器,应用不能独立安装。
+
'''项目的根目录''' (包含 <code>manage.py</code> 的目录)通常是所有未单独安装的项目应用程序的容器。
  
术语 '''application''' 指的是提供了一些功能的 Python 包。应用 [[../../intro/reusable-apps|<span class="doc">可在多个项目中重用</span>]]。
+
术语 '''application''' 描述了一个提供一些功能集的 Python 包。 应用程序 [[../../intro/reusable-apps|可以在各种项目中重复使用]] 。
  
应用程序包括模型,视图,模板,模板标签,静态文件,URL,中间件等的一些组合。它们通常使用 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 选项加入到项目中,也可以使用其他机制,如 URLconf, [[../settings#std-setting-MIDDLEWARE|<code>MIDDLEWARE</code>]] 配置或模板继承。
+
应用程序包括模型、视图、模板、模板标签、静态文件、URL、中间件等的某种组合。 它们通常通过 [[#id1|:setting:`INSTALLED_APPS`]] 设置和其他机制(如 URLconfs、[[#id3|:setting:`MIDDLEWARE`]] 设置或模板继承)连接到项目中。
  
了解Django应用程序是一组与框架的各个部分进行交互的代码,这一点很重要。没有诸如“应用程序”对象之类的东西。但是,在某些Django需要与已安装的应用程序进行交互的地方,主要用于配置和内省。这就是为什么应用程序注册表在每个安装的应用程序的:class:[[#id1|<span id="id2" class="problematic">`</span>]]~django.apps.AppConfig`实例中维护元数据的原因。
+
Django 应用程序是一组与框架的各个部分交互的代码,理解这一点很重要。 没有 <code>Application</code> 对象这样的东西。 但是,Django 需要在一些地方与已安装的应用程序进行交互,主要用于配置和自省。 这就是应用程序注册表为每个已安装应用程序在 [[#django.apps.AppConfig|AppConfig]] 实例中维护元数据的原因。
  
一个项目包可以自由的作为一个应用程序并包含一些模型等(前提是,需要把它加入 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]])。
+
没有限制项目包不能也被视为应用程序并具有模型等。 (这需要将它添加到 [[#id5|:setting:`INSTALLED_APPS`]])。
  
  
第42行: 第43行:
 
== 配置应用程序 ==
 
== 配置应用程序 ==
  
配置一个应用程序,需要继承 [[#django.apps.AppConfig|<code>AppConfig</code>]],将子类的点式路径加入 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 中。
+
要配置应用程序,子类 [[#django.apps.AppConfig|AppConfig]] 并将该子类的虚线路径放在 [[#id7|:setting:`INSTALLED_APPS`]] 中。
  
当 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 包含当前路径到一个应用程序模块的路径时,Django 会检查该模块下的 <code>default_app_config</code> 变量。
+
当 [[#id9|:setting:`INSTALLED_APPS`]] 包含应用程序模块的虚线路径时,Django 会检查该模块中的 <code>default_app_config</code> 变量。
  
如果已经定义,它是当前路径到到达该应用程序子类 [[#django.apps.AppConfig|<code>AppConfig</code>]] 的路径。
+
如果已定义,则它是该应用程序的 [[#django.apps.AppConfig|AppConfig]] 子类的虚线路径。
  
如果没有 <code>default_app_config</code>,Django 会使用基类 [[#django.apps.AppConfig|<code>AppConfig</code>]]
+
如果没有 <code>default_app_config</code>,Django 使用基本的 [[#django.apps.AppConfig|AppConfig]] 类。
  
<code>default_app_config</code> 允许 Django 1.7 之前的应用程序(例如 <code>django.contrib.admin</code>)在不要求用户更新 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 的情况下就可以加入 [[#django.apps.AppConfig|<code>AppConfig</code>]] 特性。
+
<code>default_app_config</code> 允许早于 Django 1.7 的应用程序,例如 <code>django.contrib.admin</code> 选择加入 [[#django.apps.AppConfig|AppConfig]] 功能,而无需用户更新他们的 [[#id11|:setting:`INSTALLED_APPS`]] ]
  
新的应用程序应该避免使用 <code>default_app_config</code>。相反,它们应该在 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 中显式地配置对应 [[#django.apps.AppConfig|<code>AppConfig</code>]] 子类的完整点式路径。
+
新应用程序应避免 <code>default_app_config</code>。 相反,他们应该要求在 [[#id13|:setting:`INSTALLED_APPS`]] 中明确配置适当的 [[#django.apps.AppConfig|AppConfig]] 子类的虚线路径。
  
 
<div id="for-application-authors" class="section">
 
<div id="for-application-authors" class="section">
  
=== 对于应用作者 ===
+
=== 对于应用程序作者 ===
  
如果您正在创建一个名为 “Rock”n“roll” 的可插拔应用程序,那么这边将告诉您将如何为管理后台提供一个合适的名称:
+
如果您正在创建一个名为“Rock'n'roll”的可插拔应用程序,以下是您为管理员提供正确名称的方法:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第64行: 第65行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># rock_n_roll/apps.py
+
<syntaxhighlight lang="python"># rock_n_roll/apps.py
  
 
from django.apps import AppConfig
 
from django.apps import AppConfig
第70行: 第71行:
 
class RockNRollConfig(AppConfig):
 
class RockNRollConfig(AppConfig):
 
     name = 'rock_n_roll'
 
     name = 'rock_n_roll'
     verbose_name = &quot;Rock ’n’ roll&quot;</pre>
+
     verbose_name = "Rock ’n’ roll"</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
你可以通过如下方式使应用程序默认加载这个 [[#django.apps.AppConfig|<code>AppConfig</code>]]:
+
你可以让你的应用程序默认加载这个 [[#django.apps.AppConfig|AppConfig]] 子类,如下所示:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第81行: 第82行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># rock_n_roll/__init__.py
+
<syntaxhighlight lang="python"># rock_n_roll/__init__.py
  
default_app_config = 'rock_n_roll.apps.RockNRollConfig'</pre>
+
default_app_config = 'rock_n_roll.apps.RockNRollConfig'</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
当 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 包含 <code>'rock_n_roll'</code> 时会使用 <code>RockNRollConfig</code>。这允许你充分利用 [[#django.apps.AppConfig|<code>AppConfig</code>]] 的功能特性,无需使你的用户去更新他们的 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 配置。除此之外,最好避免使用 <code>default_app_config</code>,而是使用后续介绍的在 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 中指定应用配置类。
+
当 [[#id15|:setting:`INSTALLED_APPS`]] 包含 <code>'rock_n_roll'</code> 时,这将导致使用 <code>RockNRollConfig</code>。 这允许您使用 [[#django.apps.AppConfig|AppConfig]] 功能,而无需您的用户更新他们的 [[#id17|:setting:`INSTALLED_APPS`]] 设置。 除了这个用例,最好避免使用 <code>default_app_config</code>,而是在 [[#id19|:setting:`INSTALLED_APPS`]] 中指定应用配置类,如下所述。
  
当然,也可以让你的用户把 'rock_n_roll.apps.RockNRollConfig' 放到他们的 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 配置文件中。你甚至可以提供具有不同行为的 [[#django.apps.AppConfig|<code>AppConfig</code>]] 的子类,让用户选择他们所需要的,将其加入到 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 配置中。
+
当然,您也可以告诉您的用户将 <code>'rock_n_roll.apps.RockNRollConfig'</code> 放在他们的 [[#id21|:setting:`INSTALLED_APPS`]] 设置中。 您甚至可以提供多个具有不同行为的不同 [[#django.apps.AppConfig|AppConfig]] 子类,并允许您的用户通过他们的 [[#id23|:setting:`INSTALLED_APPS`]] 设置来选择一个。
  
惯例是将配置类放在应用程序名为 <code>apps</code> 的子模块中。但是,这不是 Django 强制规定的。
+
推荐的约定是将配置类放在名为 <code>apps</code> 的应用程序子模块中。 但是,这不是由 Django 强制执行的。
  
你必须包含 attr:~django.apps.AppConfig.name 属性,Django 用它决定这个配置会应用于哪个应用。你定义任何在 [[#django.apps.AppConfig|<code>AppConfig</code>]] API 参考中记录的属性。
+
您必须为 Django 包含 [[#django.apps.AppConfig.name|name]] 属性以确定此配置适用于哪个应用程序。 您可以定义 [[#django.apps.AppConfig|AppConfig]] API 参考中记录的任何属性。
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
若你在应用的 <code>__init__.py</code> 中导入了应用注册信息,名称 <code>apps</code> 会与子模块 <code>apps</code> 冲突。最好的办法是将此段带入移入子模块,再导入它。折中方案是导入后取个别名:
+
如果您的代码在应用程序的 <code>__init__.py</code> 中导入应用程序注册表,则名称 <code>apps</code> 将与 <code>apps</code> 子模块冲突。 最佳实践是将该代码移动到子模块并导入它。 解决方法是以不同的名称导入注册表:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第106行: 第107行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.apps import apps as django_apps</pre>
+
<syntaxhighlight lang="python">from django.apps import apps as django_apps</syntaxhighlight>
  
 
</div>
 
</div>
第117行: 第118行:
 
<div id="for-application-users" class="section">
 
<div id="for-application-users" class="section">
  
=== 对于应用使用者 ===
+
=== 对于应用程序用户 ===
  
项目中直接使用 &quot;Rock ’n’ roll&quot;,其名字会是 <code>anthology</code>,但是你可能期望显示 &quot;Jazz Manouche&quot;,这需要你提供自定义配置:
+
如果您在名为 <code>anthology</code> 的项目中使用“Rock 'n'roll”,但您希望它显示为“Jazz Manouche”,您可以提供您自己的配置:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第125行: 第126行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># anthology/apps.py
+
<syntaxhighlight lang="python"># anthology/apps.py
  
 
from rock_n_roll.apps import RockNRollConfig
 
from rock_n_roll.apps import RockNRollConfig
  
 
class JazzManoucheConfig(RockNRollConfig):
 
class JazzManoucheConfig(RockNRollConfig):
     verbose_name = &quot;Jazz Manouche&quot;
+
     verbose_name = "Jazz Manouche"
  
 
# anthology/settings.py
 
# anthology/settings.py
第137行: 第138行:
 
     'anthology.apps.JazzManoucheConfig',
 
     'anthology.apps.JazzManoucheConfig',
 
     # ...
 
     # ...
]</pre>
+
]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
同样,在名为 <code>app</code> 的子模块中定义项目配置类是一种约定俗成的惯例,但不强求。
+
同样,在名为 <code>apps</code> 的子模块中定义特定于项目的配置类是约定,而不是要求。
  
  
第152行: 第153行:
 
== 应用配置 ==
 
== 应用配置 ==
  
; ''class'' <code>AppConfig</code>[[../_modules/django/apps/config.html#AppConfig|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">AppConfig</span></span>
: 应用程序配置对象存储了应用的元数据。某些属性可以在 [[#django.apps.AppConfig|<code>AppConfig</code>]] 的子类中配置。而其它 Django 设置好的配置是只读的。
+
: 应用程序配置对象存储应用程序的元数据。 一些属性可以在 [[#django.apps.AppConfig|AppConfig]] 子类中配置。 其他的由 Django 设置并且是只读的。
  
 
<div id="configurable-attributes" class="section">
 
<div id="configurable-attributes" class="section">
  
=== 可配置属性 ===
+
=== 可配置的属性 ===
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>name</code></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">name</span></span></dt>
<dd><p>指向此应用的完整的 Python 格式的路径,如 <code>'django.contrib.admin'</code>。</p>
+
<dd><p>应用程序的完整 Python 路径,例如 <code>'django.contrib.admin'</code>。</p>
<p>此属性定义配置适用的应用程序。每个 'django.apps.AppConfig` 子类都必须包含此项。</p>
+
<p>此属性定义配置适用于哪个应用程序。 它必须在所有 [[#django.apps.AppConfig|AppConfig]] 子类中设置。</p>
<p>它必须在整个 Django 项目中唯一。</p></dd></dl>
+
<p>它在 Django 项目中必须是唯一的。</p></dd></dl>
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>label</code></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">label</span></span></dt>
<dd><p>应用简称,如 <code>'admin'</code></p>
+
<dd><p>应用程序的简称,例如 <code>'admin'</code></p>
<p>此属性允许在两个应用标签冲突时重命名其中一个的标签名。默认是 <code>name</code> 的最后一段。必须是一个有效的 Python 标识符。</p>
+
<p>当两个应用程序具有冲突的标签时,此属性允许重新标记应用程序。 默认为 <code>name</code> 的最后一个组件。 它应该是一个有效的 Python 标识符。</p>
<p>它必须在整个 Django 项目中唯一。</p></dd></dl>
+
<p>它在 Django 项目中必须是唯一的。</p></dd></dl>
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>verbose_name</code></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">verbose_name</span></span></dt>
<dd><p>应用容易被人理解的名称,如 &quot;Administration&quot;。</p>
+
<dd><p>应用程序的人类可读名称,例如 “行政”。</p>
<p>此属性默认值为 <code>label.title()</code>。</p></dd></dl>
+
<p>该属性默认为 <code>label.title()</code>。</p></dd></dl>
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>path</code></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">path</span></span></dt>
<dd><p>应用目录的文件系统路径,如 <code>'/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'</code>。</p>
+
<dd><p>应用程序目录的文件系统路径,例如 <code>'/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'</code>。</p>
<p>大多数情况下,Django 能自动检测并设置此属性,但你也能在 [[#django.apps.AppConfig|<code>AppConfig</code>]] 子类中申明此属性,显式地重写它。很少情况下要这么做;例如,若应用包是一个拥有多个路径的 [[#namespace-package|命名空间]]。</p></dd></dl>
+
<p>在大多数情况下,Django 可以自动检测并设置它,但您也可以提供显式覆盖作为 [[#django.apps.AppConfig|AppConfig]] 子类上的类属性。 在某些情况下,这是必需的; 例如,如果应用程序包是具有多个路径的 [[#namespace-package|命名空间包]] 。</p></dd></dl>
  
  
第187行: 第188行:
 
=== 只读属性 ===
 
=== 只读属性 ===
  
; <code>AppConfig.</code><code>module</code>
+
; <span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">module</span></span>
: 应用的根模块,如 <code>&lt;module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'&gt;</code>。
+
: 应用程序的根模块,例如 <code>&lt;module 'django.contrib.admin' from 'django/contrib/admin/__init__.py'&gt;</code>。
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>models_module</code></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">models_module</span></span></dt>
<dd><p>包含模型的模块,如 <code>&lt;module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'&gt;</code>。</p>
+
<dd><p>包含模型的模块,例如 <code>&lt;module 'django.contrib.admin.models' from 'django/contrib/admin/models.py'&gt;</code>。</p>
<p>应用不包含 <code>models</code> 模块时,可能是 <code>None</code>。注意,数据库关联的信号,例如 [[../signals#django.db.models.signals|<code>pre_migrate</code>]] 和 [[../signals#django.db.models.signals|<code>post_migrate</code>]] 仅在应用有 <code>models</code> 模块时发出。</p></dd></dl>
+
<p>如果应用程序不包含 <code>models</code> 模块,则它可能是 <code>None</code>。 请注意,数据库相关信号(例如 [[../signals#django.db.models.signals|pre_migrate]] 和 [[../signals#django.db.models.signals|post_migrate]])仅针对具有 <code>models</code> 模块的应用程序发出。</p></dd></dl>
  
  
第202行: 第203行:
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>get_models</code><span class="sig-paren">(</span><span class="sig-paren">)</span>[[../_modules/django/apps/config.html#AppConfig.get_models|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">get_models</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>为该应用返回一个可迭代的 [[../models/instances#django.db.models|<code>Model</code>]] 类。</p>
+
<dd><p>返回此应用程序的 [[../models/instances#django.db.models|Model]] 类的可迭代对象。</p>
<p>要求完整填写应用注册信息。</p></dd></dl>
+
<p>需要完全填充应用程序注册表。</p></dd></dl>
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>get_model</code><span class="sig-paren">(</span>''<span class="n">model_name</span>'', ''<span class="n">require_ready</span><span class="o">=</span><span class="default_value">True</span>''<span class="sig-paren">)</span>[[../_modules/django/apps/config.html#AppConfig.get_model|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">get_model</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">model_name</span></span>'', ''<span class="n"><span class="pre">require_ready</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>返回给出的 <code>model_name</code> 的 [[../models/instances#django.db.models|<code>Model</code>]]。 <code>model_name</code> 是大小写敏感的。</p>
+
<dd><p>返回具有给定 <code>model_name</code> 的 [[../models/instances#django.db.models|Model]]。 <code>model_name</code> 不区分大小写。</p>
<p>如果应用中不存在此模块,则抛出 LookupError 异常。</p>
+
<p>如果此应用程序中不存在此类模型,则引发 <code>LookupError</code>。</p>
<p><code>require_ready</code> 参数为 <code>False</code> 的情况下,都必须完整设置注册信息。 <code>require_ready</code> 行为与 [[#django.apps.apps.get_model|<code>apps.get_model()</code>]] 一致。</p></dd></dl>
+
<p>除非 <code>require_ready</code> 参数设置为 <code>False</code>,否则需要完全填充应用程序注册表。 <code>require_ready</code> 的行为与 [[#django.apps.apps.get_model|apps.get_model()]] 完全一样。</p></dd></dl>
  
 
<dl>
 
<dl>
<dt><code>AppConfig.</code><code>ready</code><span class="sig-paren">(</span><span class="sig-paren">)</span>[[../_modules/django/apps/config.html#AppConfig.ready|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">AppConfig.</span></span><span class="sig-name descname"><span class="pre">ready</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>子类可以重写此方法来执行类似注册信号的初始化任务。只要注册表被填满就会调用此方法。</p>
+
<dd><p>子类可以覆盖此方法来执行初始化任务,例如注册信号。 一旦注册表被完全填充,它就会被调用。</p>
<p>虽然你不能在定义 [[#django.apps.AppConfig|<code>AppConfig</code>]] 类的模型层导入模型,但可以在 <code>ready()</code> 中导入,通过 <code>import</code> 语句或 [[#django.apps.AppConfig.get_model|<code>get_model()</code>]]。</p>
+
<p>尽管您无法在定义了 [[#django.apps.AppConfig|AppConfig]] 类的模块级别导入模型,但您可以在 <code>ready()</code> 中使用 <code>import</code> 语句或 [[#django.apps.AppConfig.get_model|导入它们get_model()]]。</p>
<p>若你正在注册 [[../signals#module-django.db.models|<code>model signals</code>]],你可以通过字符串标签追踪发信者,而不是用模型类。</p>
+
<p>如果您正在注册 [[../signals#module-django.db.models|模型信号]] ,您可以通过其字符串标签而不是使用模型类本身来引用发送者。</p>
<p>举例:</p>
+
<p>例子:</p>
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
  
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.apps import AppConfig
+
<syntaxhighlight lang="python">from django.apps import AppConfig
 
from django.db.models.signals import pre_save
 
from django.db.models.signals import pre_save
  
第235行: 第236行:
  
 
         # registering signals with the model's string label
 
         # registering signals with the model's string label
         pre_save.connect(receiver, sender='app_label.MyModel')</pre>
+
         pre_save.connect(receiver, sender='app_label.MyModel')</syntaxhighlight>
  
 
</div>
 
</div>
第243行: 第244行:
  
 
<p>警告</p>
 
<p>警告</p>
<p>尽管可以向上面介绍的那样访问模型类,但是要避免在 [[#django.apps.AppConfig.ready|<code>ready()</code>]] 实现中与数据库交互。这包括了那些会通过 <code>django.db.connection</code> 执行查询 ([[../models/instances#django.db.models.Model|<code>save()</code>]][[../models/instances#django.db.models.Model|<code>delete()</code>]],管理器方法,等等) 和原生查询的模型方法。你的 [[#django.apps.AppConfig.ready|<code>ready()</code>]] 方法会在每个管理命令初始化阶段被执行。例如,虽然测试数据库的配置与生成环境配置是分开的, <code>manager.py test</code> 仍会对 '''生产环境''' 数据库执行一些查询操作。</p>
+
<p>尽管您可以如上所述访问模型类,但请避免在 [[#django.apps.AppConfig.ready|ready()]] 实现中与数据库交互。 这包括执行查询的模型方法([[../models/instances#django.db.models.Model|save()]][[../models/instances#django.db.models.Model|delete()]]、管理器方法等),以及通过 <code>django.db.connection</code> 的原始 SQL 查询。 您的 [[#django.apps.AppConfig.ready|ready()]] 方法将在每个管理命令启动期间运行。 例如,即使测试数据库配置与生产设置分开,<code>manage.py test</code> 仍会针对您的 '''生产''' 数据库执行一些查询!</p>
  
 
</div>
 
</div>
 
<div class="admonition note">
 
<div class="admonition note">
  
<p>注解</p>
+
<p>笔记</p>
<p>在普通的初始化进程中, <code>ready</code> 方法仅被 Django 调用一次。但在一些特殊情况下,特别是针对已安装应用的测试中,可以会多次调用 <code>ready</code>。这种情况下,在 <code>AppConfig</code> 类中编写幂等方法或放入一个标志,避免那些只需运行一次的代码被多次执行。</p>
+
<p>在通常的初始化过程中,<code>ready</code> 方法只会被 Django 调用一次。 但是在某些极端情况下,尤其是在摆弄已安装应用程序的测试中,可能会多次调用 <code>ready</code>。 在这种情况下,要么编写幂等方法,要么在您的 <code>AppConfig</code> 类上放置一个标志,以防止重新运行应该只执行一次的代码。</p>
  
 
</div></dd></dl>
 
</div></dd></dl>
第260行: 第261行:
 
=== 命名空间包作为应用程序 ===
 
=== 命名空间包作为应用程序 ===
  
没有__init__.py文件的Python包被称为“命名空间包”,并且可能分布在sys.path上不同位置的多个目录中(见:pep:'420')
+
没有 <code>__init__.py</code> 文件的 Python 包被称为“命名空间包”,可能分布在 <code>sys.path</code> 上不同位置的多个目录中(参见 <span id="index-0" class="target"></span>[https://www.python.org/dev/peps/pep-0420 PEP 420] ])。
  
Django应用程序需要一个单一的基本文件系统路径,Django(取决于配置)将在其中搜索模板、静态资产等。因此,只有在以下情况之一为真时,命名空间包才可能是Django应用程序:
+
Django 应用程序需要一个基本文件系统路径,Django(取决于配置)将在其中搜索模板、静态资产等。 因此,如果满足以下任一条件,命名空间包可能只是 Django 应用程序:
  
# 名称空间包实际上只有一个位置(即不分布在多个目录中)。
+
# 命名空间包实际上只有一个位置(即 不分布在多个目录中。)
# The [[#django.apps.AppConfig|<code>AppConfig</code>]] class used to configure the application has a [[#django.apps.AppConfig.path|<code>path</code>]] class attribute, which is the absolute directory path Django will use as the single base path for the application.
+
# 用于配置应用程序的 [[#django.apps.AppConfig|AppConfig]] 类有一个 [[#django.apps.AppConfig.path|path]] 类属性,这是 Django 将用作应用程序的单个基本路径的绝对目录路径。
  
If neither of these conditions is met, Django will raise
+
如果这两个条件都不满足,Django 将引发 [[../exceptions#django.core.exceptions|ImproperlyConfigured]]
[[../exceptions#django.core.exceptions|<code>ImproperlyConfigured</code>]].
 
  
  
第276行: 第276行:
 
<div id="application-registry" class="section">
 
<div id="application-registry" class="section">
  
== 注册应用 ==
+
== 应用注册 ==
  
; <code>apps</code>
+
; <span class="sig-name descname"><span class="pre">apps</span></span>
: 应用程序注册表提供以下公共API。以下未列出的方法被视为私有方法,可能会更改,恕不另行通知。
+
: 应用程序注册表提供以下公共 API。 下面未列出的方法被视为私有方法,可能会更改,恕不另行通知。
  
; <code>apps.</code><code>ready</code>
+
; <span class="sig-prename descclassname"><span class="pre">apps.</span></span><span class="sig-name descname"><span class="pre">ready</span></span>
: Boolean attribute that is set to <code>True</code> after the registry is fully populated and all [[#django.apps.AppConfig.ready|<code>AppConfig.ready()</code>]] methods are called.
+
: 在注册表完全填充并调用所有 [[#django.apps.AppConfig.ready|AppConfig.ready()]] 方法后设置为 <code>True</code> 的布尔属性。
  
; <code>apps.</code><code>get_app_configs</code><span class="sig-paren">(</span><span class="sig-paren">)</span>
+
; <span class="sig-prename descclassname"><span class="pre">apps.</span></span><span class="sig-name descname"><span class="pre">get_app_configs</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span>
: 返回一个由django.apps.AppConfig类实例组成的可迭代对象
+
: 返回 [[#django.apps.AppConfig|AppConfig]] 实例的迭代。
  
; <code>apps.</code><code>get_app_config</code><span class="sig-paren">(</span>''<span class="n">app_label</span>''<span class="sig-paren">)</span>
+
; <span class="sig-prename descclassname"><span class="pre">apps.</span></span><span class="sig-name descname"><span class="pre">get_app_config</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">app_label</span></span>''<span class="sig-paren">)</span>
: Returns an [[#django.apps.AppConfig|<code>AppConfig</code>]] for the application with the given <code>app_label</code>. Raises <code>LookupError</code> if no such application exists.
+
: 返回具有给定 <code>app_label</code> 的应用程序的 [[#django.apps.AppConfig|AppConfig]]。 如果不存在这样的应用程序,则引发 <code>LookupError</code>
  
; <code>apps.</code><code>is_installed</code><span class="sig-paren">(</span>''<span class="n">app_name</span>''<span class="sig-paren">)</span>
+
; <span class="sig-prename descclassname"><span class="pre">apps.</span></span><span class="sig-name descname"><span class="pre">is_installed</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">app_name</span></span>''<span class="sig-paren">)</span>
: Checks whether an application with the given name exists in the registry. <code>app_name</code> is the full name of the app, e.g. <code>'django.contrib.admin'</code>.
+
: 检查注册表中是否存在具有给定名称的应用程序。 <code>app_name</code> 是应用的全名,例如 <code>'django.contrib.admin'</code>
  
 
<dl>
 
<dl>
<dt><code>apps.</code><code>get_model</code><span class="sig-paren">(</span>''<span class="n">app_label</span>'', ''<span class="n">model_name</span>'', ''<span class="n">require_ready</span><span class="o">=</span><span class="default_value">True</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-prename descclassname"><span class="pre">apps.</span></span><span class="sig-name descname"><span class="pre">get_model</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">app_label</span></span>'', ''<span class="n"><span class="pre">model_name</span></span>'', ''<span class="n"><span class="pre">require_ready</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns the [[../models/instances#django.db.models|<code>Model</code>]] with the given <code>app_label</code>
+
<dd><p>返回具有给定 <code>app_label</code> 和 <code>model_name</code> 的 [[../models/instances#django.db.models|Model]]。 作为一种快捷方式,此方法还接受 <code>app_label.model_name</code> 形式的单个参数。 <code>model_name</code> 不区分大小写。</p>
and <code>model_name</code>. As a shortcut, this method also accepts a single
+
<p>如果不存在此类应用程序或模型,则引发 <code>LookupError</code>。 当使用不包含一个点的单个参数调用时引发 <code>ValueError</code></p>
argument in the form <code>app_label.model_name</code>. <code>model_name</code> is
+
<p>除非 <code>require_ready</code> 参数设置为 <code>False</code>,否则需要完全填充应用程序注册表。</p>
case-insensitive.</p>
+
<p><code>require_ready</code> 设置为 <code>False</code> 允许在填充应用程序注册表 [[#app-loading-process|时查找模型]] ,特别是在导入模型的第二阶段。 然后<code>get_model()</code>和导入模型效果一样。 主要用例是使用设置来配置模型类,例如 [[#id25|:setting:`AUTH_USER_MODEL`]]</p>
<p>Raises <code>LookupError</code> if no such application or model exists. Raises
+
<p><code>require_ready</code> <code>False</code> 时,<code>get_model()</code> 返回的模型类可能无法完全发挥作用(例如,反向访问器可能丢失),直到完全填充应用程序注册表。 因此,最好尽可能将 <code>require_ready</code> 保留为默认值 <code>True</code></p></dd></dl>
<code>ValueError</code> when called with a single argument that doesn't contain
 
exactly one dot.</p>
 
<p>Requires the app registry to be fully populated unless the
 
<code>require_ready</code> argument is set to <code>False</code>.</p>
 
<p>Setting <code>require_ready</code> to <code>False</code> allows looking up models
 
[[#app-loading-process|<span class="std std-ref">while the app registry is being populated</span>]],
 
specifically during the second phase where it imports models. Then
 
<code>get_model()</code> has the same effect as importing the model. The main use
 
case is to configure model classes with settings, such as
 
[[../settings#std-setting-AUTH_USER_MODEL|<code>AUTH_USER_MODEL</code>]].</p>
 
<p>When <code>require_ready</code> is <code>False</code>, <code>get_model()</code> returns a model class
 
that may not be fully functional (reverse accessors may be missing, for
 
example) until the app registry is fully populated. For this reason, it's
 
best to leave <code>require_ready</code> to the default value of <code>True</code> whenever
 
possible.</p></dd></dl>
 
  
  
第321行: 第306行:
  
 
<span id="app-loading-process"></span>
 
<span id="app-loading-process"></span>
== 初始化进程 ==
+
== 初始化过程 ==
  
 
<div id="how-applications-are-loaded" class="section">
 
<div id="how-applications-are-loaded" class="section">
  
=== 应用是如何被加载的 ===
+
=== 如何加载应用程序 ===
  
Django 启动后, [[#django.setup|<code>django.setup()</code>]] 负责配置应用注册信息。
+
Django 启动时,[[#django.setup|django.setup()]] 负责填充应用程序注册表。
  
 
<dl>
 
<dl>
<dt><code>setup</code><span class="sig-paren">(</span>''<span class="n">set_prefix</span><span class="o">=</span><span class="default_value">True</span>''<span class="sig-paren">)</span>[[../_modules/django.html#setup|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt><span class="sig-name descname"><span class="pre">setup</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">set_prefix</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>配置 Django:</p>
+
<dd><p>通过以下方式配置 Django:</p>
 
<ul>
 
<ul>
<li><p>加载配置。</p></li>
+
<li><p>加载设置。</p></li>
<li><p>设置日志。</p></li>
+
<li><p>设置日志记录。</p></li>
<li><p><code>set_prefix</code> 为 True,为 URL 处理器脚本增加前缀 [[../settings#std-setting-FORCE_SCRIPT_NAME|<code>FORCE_SCRIPT_NAME</code>]],若未定义此项,则使用 <code>/</code>。</p></li>
+
<li><p>如果 <code>set_prefix</code> 为 True,则将 URL 解析器脚本前缀设置为 [[#id27|:setting:`FORCE_SCRIPT_NAME`]](如果已定义),否则设置为 <code>/</code>。</p></li>
<li><p>初始化应用注册</p></li></ul>
+
<li><p>初始化应用程序注册表。</p></li></ul>
  
<p>这个函数会被自动调用。</p>
+
<p>这个函数是自动调用的:</p>
 
<ul>
 
<ul>
<li><p>当通过 Django 的 WSGI 支持运行 HTTP 服务。</p></li>
+
<li><p>通过 Django 的 WSGI 支持运行 HTTP 服务器时。</p></li>
<li><p>调用一个管理命令时。</p></li></ul>
+
<li><p>调用管理命令时。</p></li></ul>
  
<p>在其他情况下,必须显式调用它,例如在纯 Python 脚本中。</p></dd></dl>
+
<p>在其他情况下必须显式调用它,例如在纯 Python 脚本中。</p></dd></dl>
  
应用注册的初始化过程分三个阶段完成。在每个阶段,Django 根据应用在 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 中的顺序依次处理。
+
应用程序注册表分三个阶段进行初始化。 在每个阶段,Django 按照 [[#id29|:setting:`INSTALLED_APPS`]] 的顺序处理所有应用程序。
  
 
<ol>
 
<ol>
<li><p>首先,Django 导入 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] 中各项条目。</p>
+
<li><p>首先 Django 导入 [[#id31|:setting:`INSTALLED_APPS`]] 中的每个项目。</p>
<p>If it's an application configuration class, Django imports the root package
+
<p>如果是应用程序配置类,Django 会导入应用程序的根包,由其 [[#django.apps.AppConfig.name|name]] 属性定义。 如果是 Python 包,Django 会创建一个默认的应用程序配置。</p>
of the application, defined by its [[#django.apps.AppConfig.name|<code>name</code>]] attribute. If
+
<p>''在此阶段,您的代码不应导入任何模型!''</p>
it's a Python package, Django creates a default application configuration.</p>
+
<p>换句话说,您的应用程序的根包和定义您的应用程序配置类的模块不应导入任何模型,即使是间接导入。</p>
<p>''在这情况下,你的代码不应该导入任何模型!''</p>
+
<p>严格来说,Django 允许在加载应用程序配置后导入模型。 但是,为了避免对[[#id33|:setting:`INSTALLED_APPS`]]的顺序进行不必要的限制,强烈建议在此阶段不要导入任何模型。</p>
<p>换句话说,应用程序的根包和定义应用程序配置类的模块不能导入任何模型,即使是间接导入。</p>
+
<p>此阶段完成后,在应用程序配置(如 [[#django.apps.apps.get_app_config|get_app_config()]])上运行的 API 就可以使用了。</p></li>
<p>严格来说,一旦应用配置完成加载后,Django 是允许导入模型。然而为了避免不必要的 [[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]], 顺序约束。强烈建议在这个阶段不要导入任何模型。</p>
+
<li><p>然后 Django 尝试导入每个应用程序的 <code>models</code> 子模块,如果有的话。</p>
<p>一旦这个阶段完成,可以使用 API 对应用程序配置(如:meth:〜apps.get_app_config() )进行操作。</p></li>
+
<p>您必须在应用程序的 <code>models.py</code> 或 <code>models/__init__.py</code> 中定义或导入所有模型。 否则,此时应用程序注册表可能未完全填充,这可能导致 ORM 出现故障。</p>
<li><p>然后 Django 尝试导入每个存在模型的应用程序中,继承了``models``的所有子模型。</p>
+
<p>此阶段完成后,可在 [[#django.apps.apps.get_model|get_model()]] 等模型上运行的 API 变得可用。</p></li>
<p>您必须在应用程序的“models.py”或“models / __ init __。py”中定义或导入所有模型。 否则,此时应用程序注册表可能不会完全加载,这可能会导致ORM出现故障。</p>
+
<li><p>最后 Django 运行每个应用程序配置的 [[#django.apps.AppConfig.ready|ready()]] 方法。</p></li></ol>
<p>此步骤完成后,操作模型的 API,例如 [[#django.apps.apps.get_model|<code>get_model()</code>]],就可以使用了。</p></li>
 
<li><p>最后,Django运行每个应用程序配置的:meth:[[#id1|<span id="id2" class="problematic">`</span>]]〜AppConfig.ready()`方法。</p></li></ol>
 
  
  
第366行: 第349行:
  
 
<span id="applications-troubleshooting"></span>
 
<span id="applications-troubleshooting"></span>
=== 错误调试 ===
+
=== 故障排除 ===
  
在初始化期间,这里有一些常见的错误你可能会遇上。
+
以下是您在初始化过程中可能遇到的一些常见问题:
  
 
<ul>
 
<ul>
<li><p>[[../exceptions#django.core.exceptions|<code>AppRegistryNotReady</code>]]: This happens when
+
<li><p>[[../exceptions#django.core.exceptions|AppRegistryNotReady]]:当导入应用程序配置或模型模块触发依赖于应用程序注册表的代码时会发生这种情况。</p>
importing an application configuration or a models module triggers code that
+
<p>例如,[[../utils#django.utils.translation|gettext()]] 使用应用程序注册表在应用程序中查找翻译目录。 要在导入时进行翻译,您需要改为 [[../utils#django.utils.translation|gettext_lazy()]]。 (使用 [[../utils#django.utils.translation|gettext()]] 将是一个错误,因为翻译会在导入时发生,而不是根据活动语言在每个请求时发生。)</p>
depends on the app registry.</p>
+
<p>在模型模块中导入时使用 ORM 执行数据库查询也会触发此异常。 在所有模型都可用之前,ORM 无法正常运行。</p>
<p>For example, [[../utils#django.utils.translation|<code>gettext()</code>]] uses the app
+
<p>如果您忘记在独立 Python 脚本中调用 [[#django.setup|django.setup()]],也会发生此异常。</p></li>
registry to look up translation catalogs in applications. To translate at
+
<li><p><code>ImportError: cannot import name ...</code> 如果导入序列以循环结束,则会发生这种情况。</p>
import time, you need [[../utils#django.utils.translation|<code>gettext_lazy()</code>]]
+
<p>为了消除此类问题,您应该尽量减少模型模块之间的依赖关系,并在导入时尽可能少做工作。 为了避免在导入时执行代码,您可以将其移动到函数中并缓存其结果。 代码将在您第一次需要其结果时执行。 这个概念被称为“懒惰评估”。</p></li>
instead. (Using [[../utils#django.utils.translation|<code>gettext()</code>]] would be a bug,
+
<li><p><code>django.contrib.admin</code> 在已安装的应用程序中自动执行 <code>admin</code> 模块的自动发现。 为了防止它,改变你的 [[#id35|:setting:`INSTALLED_APPS`]] 以包含 <code>'django.contrib.admin.apps.SimpleAdminConfig'</code> 而不是 <code>'django.contrib.admin'</code></p></li></ul>
because the translation would happen at import time, rather than at each
 
request depending on the active language.)</p>
 
<p>Executing database queries with the ORM at import time in models modules
 
will also trigger this exception. The ORM cannot function properly until all
 
models are available.</p>
 
<p>如果你忘记在一个单独的Python脚本中调用函数`django.setup()`,也会发生异常。</p></li>
 
<li><p><code>ImportError: cannot import name ...</code> This happens if the import sequence
 
ends up in a loop.</p>
 
<p>为了消除这些问题,您应该最大限度地减少模型模块之间的依赖关系,并在导入时尽可能减少复杂度。 为了避免在导入时执行代码,可以将其移入函数并缓存结果。 代码将在您首次需要结果时执行。 这个概念被称为“惰性求值”。</p></li>
 
<li><p><code>django.contrib.admin</code> automatically performs autodiscovery of <code>admin</code>
 
modules in installed applications. To prevent it, change your
 
[[../settings#std-setting-INSTALLED_APPS|<code>INSTALLED_APPS</code>]] to contain
 
<code>'django.contrib.admin.apps.SimpleAdminConfig'</code> instead of
 
<code>'django.contrib.admin'</code>.</p></li></ul>
 
  
  
第399行: 第368行:
  
 
</div>
 
</div>
 +
<div class="clearer">
  
[[Category:Django 3.0.x 中文文档]]
+
 
 +
 
 +
</div>
 +
 
 +
[[Category:Django 3.0.x 文档]]

2021年10月31日 (日) 04:09的最新版本

应用

Django 包含一个已安装应用程序的注册表,用于存储配置并提供自省。 它还维护一个可用 模型 的列表。

此注册表称为 apps,它在 django.apps 中可用:

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

项目和应用

术语 project 描述了 Django Web 应用程序。 项目 Python 包主要由设置模块定义,但它通常包含其他内容。 例如,当您运行 django-admin startproject mysite 时,您将获得一个 mysite 项目目录,其中包含一个 mysite Python 包,其中包含 settings.pyurls.py , asgi.pywsgi.py。 项目包通常会扩展为包含不绑定到特定应用程序的夹具、CSS 和模板等内容。

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

术语 application 描述了一个提供一些功能集的 Python 包。 应用程序 可以在各种项目中重复使用

应用程序包括模型、视图、模板、模板标签、静态文件、URL、中间件等的某种组合。 它们通常通过 :setting:`INSTALLED_APPS` 设置和其他机制(如 URLconfs、:setting:`MIDDLEWARE` 设置或模板继承)连接到项目中。

Django 应用程序是一组与框架的各个部分交互的代码,理解这一点很重要。 没有 Application 对象这样的东西。 但是,Django 需要在一些地方与已安装的应用程序进行交互,主要用于配置和自省。 这就是应用程序注册表为每个已安装应用程序在 AppConfig 实例中维护元数据的原因。

没有限制项目包不能也被视为应用程序并具有模型等。 (这需要将它添加到 :setting:`INSTALLED_APPS`)。


配置应用程序

要配置应用程序,子类 AppConfig 并将该子类的虚线路径放在 :setting:`INSTALLED_APPS` 中。

:setting:`INSTALLED_APPS` 包含应用程序模块的虚线路径时,Django 会检查该模块中的 default_app_config 变量。

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

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

default_app_config 允许早于 Django 1.7 的应用程序,例如 django.contrib.admin 选择加入 AppConfig 功能,而无需用户更新他们的 :setting:`INSTALLED_APPS` ]。

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

对于应用程序作者

如果您正在创建一个名为“Rock'n'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'

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

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

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

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

笔记

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

from django.apps import apps as django_apps

对于应用程序用户

如果您在名为 anthology 的项目中使用“Rock 'n'roll”,但您希望它显示为“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 的子模块中定义特定于项目的配置类是约定,而不是要求。


应用配置

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

可配置的属性

AppConfig.name

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

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

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

AppConfig.label

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

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

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

AppConfig.verbose_name

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

该属性默认为 label.title()

AppConfig.path

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

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


只读属性

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_migratepost_migrate)仅针对具有 models 模块的应用程序发出。


方法

AppConfig.get_models()

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

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

AppConfig.get_model(model_name, require_ready=True)

返回具有给定 model_nameModelmodel_name 不区分大小写。

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

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

AppConfig.ready()

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

尽管您无法在定义了 AppConfig 类的模块级别导入模型,但您可以在 ready() 中使用 import 语句或 导入它们get_model()

如果您正在注册 模型信号 ,您可以通过其字符串标签而不是使用模型类本身来引用发送者。

例子:

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 的原始 SQL 查询。 您的 ready() 方法将在每个管理命令启动期间运行。 例如,即使测试数据库配置与生产设置分开,manage.py test 仍会针对您的 生产 数据库执行一些查询!

笔记

在通常的初始化过程中,ready 方法只会被 Django 调用一次。 但是在某些极端情况下,尤其是在摆弄已安装应用程序的测试中,可能会多次调用 ready。 在这种情况下,要么编写幂等方法,要么在您的 AppConfig 类上放置一个标志,以防止重新运行应该只执行一次的代码。


命名空间包作为应用程序

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

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

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

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


应用注册

apps
应用程序注册表提供以下公共 API。 下面未列出的方法被视为私有方法,可能会更改,恕不另行通知。
apps.ready
在注册表完全填充并调用所有 AppConfig.ready() 方法后设置为 True 的布尔属性。
apps.get_app_configs()
返回 AppConfig 实例的迭代。
apps.get_app_config(app_label)
返回具有给定 app_label 的应用程序的 AppConfig。 如果不存在这样的应用程序,则引发 LookupError
apps.is_installed(app_name)
检查注册表中是否存在具有给定名称的应用程序。 app_name 是应用的全名,例如 'django.contrib.admin'
apps.get_model(app_label, model_name, require_ready=True)

返回具有给定 app_labelmodel_nameModel。 作为一种快捷方式,此方法还接受 app_label.model_name 形式的单个参数。 model_name 不区分大小写。

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

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

require_ready 设置为 False 允许在填充应用程序注册表 时查找模型 ,特别是在导入模型的第二阶段。 然后get_model()和导入模型效果一样。 主要用例是使用设置来配置模型类,例如 :setting:`AUTH_USER_MODEL`

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


初始化过程

如何加载应用程序

当 Django 启动时,django.setup() 负责填充应用程序注册表。

setup(set_prefix=True)

通过以下方式配置 Django:

  • 加载设置。

  • 设置日志记录。

  • 如果 set_prefix 为 True,则将 URL 解析器脚本前缀设置为 :setting:`FORCE_SCRIPT_NAME`(如果已定义),否则设置为 /

  • 初始化应用程序注册表。

这个函数是自动调用的:

  • 通过 Django 的 WSGI 支持运行 HTTP 服务器时。

  • 调用管理命令时。

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

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

  1. 首先 Django 导入 :setting:`INSTALLED_APPS` 中的每个项目。

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

    在此阶段,您的代码不应导入任何模型!

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

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

    此阶段完成后,在应用程序配置(如 get_app_config())上运行的 API 就可以使用了。

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

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

    此阶段完成后,可在 get_model() 等模型上运行的 API 变得可用。

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


故障排除

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

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

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

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

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

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

    为了消除此类问题,您应该尽量减少模型模块之间的依赖关系,并在导入时尽可能少做工作。 为了避免在导入时执行代码,您可以将其移动到函数中并缓存其结果。 代码将在您第一次需要其结果时执行。 这个概念被称为“懒惰评估”。

  • django.contrib.admin 在已安装的应用程序中自动执行 admin 模块的自动发现。 为了防止它,改变你的 :setting:`INSTALLED_APPS` 以包含 'django.contrib.admin.apps.SimpleAdminConfig' 而不是 'django.contrib.admin'