Приложения
Django содержит реестр установленных приложений, который хранит конфигурацию и предоставляет возможность интроспекции. Он также поддерживает список доступных моделей.
Этот реестр называется apps, и он доступен в django.apps:
>>> from django.apps import apps
>>> apps.get_app_config('admin').verbose_name
'Administration'
Проекты и приложения
Термин проект описывает веб-приложение Django. Пакет Python проекта определяется в основном модулем настроек, но обычно содержит и другие вещи. Например, когда вы запускаете django-admin startproject mysite, вы получите каталог проекта mysite, который содержит пакет Python mysite с settings.py, urls.py, asgi.py и wsgi.py. Пакет проекта часто расширяется, чтобы включать такие вещи, как фикстуры, CSS и шаблоны, которые не привязаны к какому-либо конкретному приложению.
Корневой каталог проекта (тот, который содержит manage.py) обычно является контейнером для всех приложений проекта, которые не установлены отдельно.
Термин приложение описывает пакет Python, который предоставляет набор функций. Приложения могут быть повторно использованы в различных проектах.
Приложения включают в себя некоторую комбинацию моделей, представлений, шаблонов, тегов шаблонов, статических файлов, URL-адресов, middleware и т. д. Они обычно подключаются к проектам с помощью настройки INSTALLED_APPS и необязательно с другими механизмами, такими как URLconfs, настройкой MIDDLEWARE или наследованием шаблонов.
Важно понимать, что приложение Django — это набор кода, который взаимодействует с различными частями фреймворка. Нет такого объекта, как Application. Однако есть несколько мест, где Django должен взаимодействовать с установленными приложениями, в основном для конфигурации и интроспекции. Вот почему реестр приложений сохраняет метаданные в экземпляре AppConfig для каждого установленного приложения.
Нет ограничения на то, что пакет проекта не может также рассматриваться как приложение и иметь модели и т. д. (что потребовало бы добавления его в INSTALLED_APPS).
Настройка приложений
Чтобы настроить приложение, необходимо унаследовать от класса AppConfig и поместить полное имя этого класса в настройку INSTALLED_APPS.
Когда 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. Вместо этого им необходимо потребовать, чтобы полное имя соответствующего подкласса AppConfig было явно указано в настройке INSTALLED_APPS.
Для авторов приложений
# 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'
Это заставит Django использовать RockNRollConfig при указании в INSTALLED_APPS значения 'rock_n_roll'. Это позволяет использовать возможности AppConfig без необходимости обновления вашей настройкой INSTALLED_APPS. Помимо этого случая, лучше избегать использования default_app_config и вместо этого указывать класс конфигурации приложения в INSTALLED_APPS, как описано ниже.
Вы также можете попросить пользователей поместить 'rock_n_roll.apps.RockNRollConfig' в настройку INSTALLED_APPS. Вы даже можете предоставить несколько различных подклассов AppConfig с различным поведением и позволить вашим пользователям выбирать один с помощью настройки INSTALLED_APPS.
Рекомендуемая конвенция состоит в том, чтобы поместить класс конфигурации в подмодуль приложения с именем apps. Однако Django этого не требует.
Вы должны включить атрибут name, чтобы Django мог определить, к какому приложению относится эта конфигурация. Вы можете определить любые атрибуты, описанные в справочнике API AppConfig.
Примечание
Если ваш код импортирует реестр приложений в __init__.py приложения, имя apps будет конфликтовать с подмодулем apps. Лучше всего переместить этот код в подмодуль и импортировать его. Обходной путь — импортировать реестр под другим именем:
from django.apps import apps as django_apps
Для пользователей приложений
Если вы используете «Rock ’n’ roll» в проекте под названием 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 — это конвенция, а не требование.
Конфигурация приложения
-
class AppConfig[source] -
Объекты конфигурации приложений хранят метаданные для приложения. Некоторые атрибуты можно настроить в подклассах
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'>.Он может быть
None, если приложение не содержит модульmodels. Обратите внимание, что сигналы, связанные с базой данных, такие какpre_migrateиpost_migrate, генерируются только для приложений, имеющих модульmodels.
Методы
-
AppConfig.get_models()[source] -
Возвращает итерируемый объект
Modelклассов для этого приложения.Требует, чтобы реестр приложений был полностью заполнен.
-
AppConfig.get_model(model_name, require_ready=True)[source] -
Возвращает
Modelс заданнымmodel_name.model_nameнечувствительно к регистру.Возбуждает
LookupError, если такой модели нет в этом приложении.Требует, чтобы реестр приложений был полностью заполнен, если аргумент
require_readyне установлен вFalse.require_readyведет себя точно так же, как вapps.get_model().
-
AppConfig.ready()[source] -
Подклассы могут переопределять этот метод для выполнения задач инициализации, таких как регистрация сигналов. Вызывается, как только реестр заполнится полностью.
Хотя вы не можете импортировать модели на уровне модуля, где определены классы
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(), методы менеджеров и т. д.), а также запросы к SQL черезdjango.db.connection. Ваш методready()будет выполняться во время запуска каждой команды управления. Например, даже если конфигурация тестовой базы данных отличается от производственных настроек,manage.py testвсе равно выполнит некоторые запросы к вашей производственной базе данных!Примечание
В стандартном процессе инициализации метод
readyвызывается Джанго только один раз. Но в некоторых особых случаях, особенно в тестах, которые изменяют установленные приложения,readyможет быть вызван более одного раза. В этом случае либо напишите идемпотентные методы, либо поместите флаг на ваши классыAppConfigдля предотвращения повторного выполнения кода, который должен выполняться ровно один раз.
Пакеты имен как приложения
Python-пакеты без файла __init__.py известны как «пакеты имен» и могут быть распределены по нескольким директориям в разных местах на sys.path (см. PEP 420).
Django-приложения требуют одного базового пути к файловой системе, где Django (в зависимости от конфигурации) будет искать шаблоны, статические файлы и т. д. Таким образом, пакеты имен могут быть Django-приложениями только в том случае, если выполняется одно из следующих условий:
- Пакет имен фактически имеет только одно местоположение (т. е. не распределен по нескольким директориям).
- Класс
AppConfig, используемый для настройки приложения, имеет атрибут классаpath, который представляет собой абсолютный путь к каталогу, который Django будет использовать в качестве единственного базового пути для приложения.
Если ни одно из этих условий не выполняется, Django возбудит ImproperlyConfigured.
Реестр приложений
-
apps -
Реестр приложений предоставляет следующий публичный API. Методы, которые не указаны ниже, считаются закрытыми и могут быть изменены без предварительного уведомления.
-
apps.ready -
Логический атрибут, который устанавливается в
Trueпосле того, как реестр заполнится полностью и все методыAppConfig.ready()будут вызваны.
-
apps.get_app_configs() -
Возвращает итерируемый объект экземпляров
AppConfig.
-
apps.get_app_config(app_label) -
Возвращает
AppConfigдля приложения с заданнымapp_label. ВозбуждаетLookupError, если такого приложения не существует.
-
apps.is_installed(app_name) -
Проверяет, существует ли в реестре приложение с данным именем.
app_name— полное имя приложения, например'django.contrib.admin'.
-
apps.get_model(app_label, model_name, require_ready=True) -
Возвращает
Modelс заданнымapp_labelиmodel_name. В качестве сокращения этот метод также принимает один аргумент в формеapp_label.model_name.model_nameнечувствительно к регистру.Возбуждает
LookupError, если такое приложение или модель не существует. ВозбуждаетValueErrorпри вызове с одним аргументом, который не содержит ровно одну точку.Требует, чтобы реестр приложений был полностью заполнен, если аргумент
require_readyне установлен вFalse.Установка
require_readyвFalseпозволяет искать модели во время заполнения реестра приложений, в частности, на второй стадии, когда импортируются модели. Затемget_model()имеет тот же эффект, что и импорт модели. Основной сценарий использования — настройка классов моделей с настройками, такими какAUTH_USER_MODEL.Когда
require_readyимеет значениеFalse,get_model()возвращает класс модели, который может не быть полностью функциональным (например, могут отсутствовать обратные аксессоры), пока реестр приложений не заполнится полностью. По этой причине лучше всего оставитьrequire_readyсо значением по умолчаниюTrueвсякий раз, когда это возможно.
Процесс инициализации
Как загружаются приложения
При запуске Django, функция django.setup() отвечает за заполнение реестра приложений.
-
setup(set_prefix=True)[source] -
Настраивает Django следующим образом:
- Загружает настройки.
- Настраивает логирование.
- Если
set_prefixравно True, устанавливает префикс скрипта URL-резолвера вFORCE_SCRIPT_NAME, если он определён, или/в противном случае. - Инициализирует реестр приложений.
Эта функция вызывается автоматически:
- При запуске HTTP-сервера через поддержку WSGI Django.
- При вызове команды управления.
В других случаях она должна вызываться явно, например, в обычных Python-скриптах.
Реестр приложений инициализируется в три этапа. На каждом этапе Django обрабатывает все приложения в порядке перечисления в INSTALLED_APPS.
-
Django сначала импортирует каждый элемент из
INSTALLED_APPS.Если это класс конфигурации приложения, Django импортирует корневой пакет приложения, определённый его атрибутом
name. Если это пакет Python, Django создаёт конфигурацию приложения по умолчанию.На данном этапе ваш код не должен импортировать модели!
Другими словами, корневые пакеты ваших приложений и модули, которые определяют классы конфигурации вашего приложения, не должны импортировать модели, даже косвенно.
Строго говоря, Django позволяет импортировать модели после загрузки их конфигурации приложения. Однако, чтобы избежать ненужных ограничений на порядок
INSTALLED_APPS, настоятельно рекомендуется не импортировать модели на этом этапе.После завершения этого этапа API, работающие с конфигурациями приложений, такие как
get_app_config(), станут доступны. -
Затем Django пытается импортировать подмодуль
modelsкаждого приложения, если он существует.Вы должны определить или импортировать все модели в подмодуле
models.pyилиmodels/__init__.pyвашего приложения. В противном случае регистр приложений может быть неполностью заполнен на этом этапе, что может привести к некорректной работе ORM.После завершения этого этапа API, работающие с моделями, такие как
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'.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.1/ref/applications/