Приложения
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).
Настройка приложений
Для настройки приложения создайте модуль 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, но хотите, чтобы он отображался как «Джаз Мануш», вы можете предоставить собственную конфигурацию:
# 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 должен содержать путь с точками к классу конфигурации, потому что он находится вне приложения и поэтому не может быть обнаружен автоматически.
Конфигурация приложения
-
class AppConfig[source] -
Объекты конфигурации приложения хранят метаданные для приложения. Некоторые атрибуты можно настроить в подклассах
AppConfig. Другие устанавливаются Django и являются только для чтения.
Настраиваемые атрибуты
-
AppConfig.name -
Полный путь к приложению в Python, например,
'django.contrib.admin'.Этот атрибут определяет, к какому приложению относится конфигурация. Он должен быть установлен во всех подклассах
AppConfig.Он должен быть уникальным в рамках проекта Django.
-
AppConfig.label -
Короткое имя приложения, например,
'admin'Этот атрибут позволяет переименовать приложение, когда у двух приложений есть конфликтующие метки. По умолчанию он устанавливается в последний компонент
name. Он должен быть допустимым идентификатором Python.Он должен быть уникальным в рамках проекта Django.
Предупреждение
Изменение этого атрибута после применения миграций для приложения приведёт к несовместимым изменениям в проекте или, в случае с повторно используемым приложением, к проблемам с существующими установками этого приложения. Это связано с тем, что
AppConfig.labelиспользуется в таблицах базы данных и файлах миграций при ссылке на приложение в списке зависимостей.
-
AppConfig.verbose_name -
Наименование приложения, понятное человеку, например, «Администрирование».
Этот атрибут по умолчанию равен
label.title().
-
AppConfig.path -
Путь к каталогу приложения в файловой системе, например,
'/usr/lib/pythonX.Y/dist-packages/django/contrib/admin'.В большинстве случаев Django может автоматически обнаружить и установить это значение, но вы также можете предоставить явное значение в качестве атрибута класса вашего подкласса
AppConfig. В некоторых ситуациях это требуется; например, если пакет приложения является пакетом с пространством имён с несколькими путями.
-
AppConfig.default -
Установите этот атрибут в значение
False, чтобы предотвратить автоматический выбор Django класса конфигурации. Это полезно, когдаapps.pyопределяет только один подклассAppConfig, но вы не хотите, чтобы Django его использовал по умолчанию.Установите этот атрибут в значение
True, чтобы указать Django, что необходимо автоматически выбрать класс конфигурации. Это полезно, когдаapps.pyопределяет более одного подклассаAppConfig, и вы хотите, чтобы Django использовал один из них по умолчанию.По умолчанию этот атрибут не установлен.
-
AppConfig.default_auto_field[source] -
Неявный тип первичного ключа, который нужно добавить к моделям в этом приложении. Вы можете использовать это для сохранения
AutoFieldв качестве типа первичного ключа для приложений третьих сторон.По умолчанию это значение
DEFAULT_AUTO_FIELD.
Только для чтения атрибуты
-
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(include_auto_created=False, include_swapped=False)[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(), методы менеджера и т.д.), а также запросы с использованиемdjango.db.connection. Ваш методready()будет выполняться во время запуска каждого командного интерфейса управления. Например, даже если конфигурация тестовой базы данных отличается от конфигурации рабочей базы данных,manage.py testвсё равно будет выполнять некоторые запросы к вашей рабочей базе данных!Примечание
В обычном процессе инициализации метод
readyвызывается Django только один раз. Но в некоторых особых случаях, особенно в тестах, которые изменяют установленные приложения,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-сервера через поддержку ASGI или WSGI Django.
- При вызове команды управления.
В других случаях, например, в обычных скриптах Python, она должна вызываться явно.
Реестр приложений инициализируется в три этапа. На каждом этапе Django обрабатывает все приложения в порядке перечисления в INSTALLED_APPS.
-
Сначала Django импортирует каждый элемент в
INSTALLED_APPS.Если это класс конфигурации приложения, Django импортирует корневой пакет приложения, определенный его атрибутом
name. Если это пакет Python, Django ищет конфигурацию приложения в подмодулеapps.py, иначе создает конфигурацию приложения по умолчанию.В этой стадии ваш код не должен импортировать модели!
Другими словами, корневые пакеты ваших приложений и модули, определяющие классы конфигурации ваших приложений, не должны импортировать модели, даже косвенно.
Строго говоря, 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'. -
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())Чтобы упростить поиск кода, который вызвал это предупреждение, вы можете заставить Python обрабатывать предупреждения как ошибки для отображения стека вызовов, например, с помощью
python -Werror manage.py shell.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/ref/applications/