Приложения
Django содержит реестр установленных приложений, который хранит конфигурацию и предоставляет возможность интроспекции. Он также поддерживает список доступных моделей.
Этот реестр просто называется apps и доступен в django.apps:
>>> from django.apps import apps
>>> apps.get_app_config('admin').verbose_name
'Admin'
Проекты и приложения
Django исторически использовал термин проект для описания установки Django. Проект определяется в первую очередь модулем настроек.
Термин приложение описывает пакет Python, предоставляющий набор функций. Приложения могут быть повторно использованы в различных проектах.
Примечание
В настоящее время эта терминология несколько запутанна, поскольку стало общепринятым использовать фразу «веб-приложение» для описания того, что соответствует проекту Django.
Приложения включают некоторую комбинацию моделей, представлений, шаблонов, тегов шаблонов, статических файлов, URL-адресов, middleware и т. д. Они обычно подключаются к проектам с помощью настройки INSTALLED_APPS и необязательно с помощью других механизмов, таких как URLconfs, настройки MIDDLEWARE_CLASSES или наследования шаблонов.
Важно понимать, что приложение Django — это просто набор кода, который взаимодействует с различными частями фреймворка. Нет такого понятия, как объект Application. Однако есть несколько мест, где Django должен взаимодействовать с установленными приложениями, главным образом для конфигурации и интроспекции. Вот почему реестр приложений сохраняет метаданные в экземпляре AppConfig для каждого установленного приложения.
Настройка приложений
Чтобы настроить приложение, следует унаследовать от 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'
Это заставит использовать RockNRollConfig при INSTALLED_APPS содержит только 'rock_n_roll'. Это позволяет использовать функции AppConfig без необходимости обновления пользователей их настройкой 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
Для пользователей приложений
Если вы используете «Рок-н-ролл» в проекте под названием anthology, но хотите, чтобы он отображался как «Джаз цыган», вы можете предоставить собственную конфигурацию:
# anthology/apps.py
from rock_n_roll.apps import RockNRollConfig
class GypsyJazzConfig(RockNRollConfig):
verbose_name = "Gypsy jazz"
# anthology/settings.py
INSTALLED_APPS = [
'anthology.apps.GypsyJazzConfig',
# ...
]
Опять же, определение проектных конфигурационных классов в подмодуле под названием 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/python3.4/dist-packages/django/contrib/admin'.В большинстве случаев Django может автоматически обнаружить и установить его, но вы также можете предоставить явную перезапись в качестве атрибута класса вашего подкласса
AppConfig. В некоторых ситуациях это необходимо; например, если пакет приложения является пакетом пространства имён с несколькими путями.
Атрибуты только для чтения
-
AppConfig.module -
Основной модуль для приложения, например
<module 'django.contrib.admin' from 'django/contrib/admin/__init__.pyc'>.
-
AppConfig.models_module -
Модуль, содержащий модели, например
<module 'django.contrib.admin.models' from 'django/contrib/admin/models.pyc'>.Он может быть
Noneесли приложение не содержит модульmodels. Обратите внимание, что сигналы, относящиеся к базе данных, такие какpre_migrateиpost_migrate, генерируются только для приложений, имеющих модульmodels.
Методы
-
AppConfig.get_models()[source] -
Возвращает итератор классов
Modelдля этого приложения.
-
AppConfig.get_model(model_name)[source] -
Возвращает
Modelс заданным именем. Вызывает исключениеLookupError, если такая модель не существует в этом приложении. Имяmodel_nameне чувствительно к регистру.
-
AppConfig.ready()[source] -
Подклассы могут переопределять этот метод для выполнения задач инициализации, таких как регистрация сигналов. Он вызывается, как только реестр полностью заполнен.
Вы не можете импортировать модели в модулях, которые определяют классы конфигурации приложений, но вы можете использовать
get_model()для доступа к классу модели по имени, например так:def ready(self): MyModel = self.get_model('MyModel')Предупреждение
Хотя вы можете получить доступ к классам моделей, как описано выше, избегайте взаимодействия с базой данных в вашей реализации
ready(). Это включает методы моделей, которые выполняют запросы (save(),delete(), методы менеджеров и т. д.), а также запросы к SQL с помощьюdjango.db.connection. Ваш методready()будет выполняться во время запуска каждой команды управления. Например, даже если конфигурация тестовой базы данных отличается от производственных настроек,manage.py testпо-прежнему будет выполнять некоторые запросы к вашей производственной базе данных!Примечание
В обычном процессе инициализации метод
readyвызывается Джанго только один раз. Но в некоторых особых случаях, особенно в тестах, которые играют с установленными приложениями,readyможет быть вызван более одного раза. В этом случае либо напишите идемпотентные методы, либо поставьте флаг на ваших классахAppConfigдля предотвращения повторного выполнения кода, который должен выполняться ровно один раз.
Пакеты именования как приложения (Python 3.3+)
Версии Python 3.3 и выше поддерживают пакеты Python без файла __init__.py. Эти пакеты известны как «пакеты именования» и могут быть распределены по нескольким каталогам в разных местах на sys.path (см. PEP 420).
Приложения Django требуют одного базового пути к файловой системе, где Джанго (в зависимости от настроек) будет искать шаблоны, статические ресурсы и т.д. Таким образом, пакеты именования могут быть приложениями Django только в том случае, если выполняется одно из следующих условий:
- Пакет именования фактически имеет только одно местоположение (то есть не распределён более чем по одному каталогу).
- Класс
AppConfig, используемый для настройки приложения, имеет атрибут классаpath, который представляет собой абсолютный путь к каталогу, который Джанго будет использовать в качестве единственного базового пути для приложения.
Если ни одно из этих условий не выполняется, Джанго поднимет исключение ImproperlyConfigured.
Регистр приложений
-
apps -
Регистр приложений предоставляет следующий публичный API. Методы, которые не указаны ниже, считаются закрытыми и могут быть изменены без уведомления.
-
apps.ready -
Булевый атрибут, который устанавливается в
Trueпри полном заполнение реестра.
-
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) -
Возвращает
Modelс заданнымapp_labelиmodel_name. В качестве сокращения этот метод также принимает один аргумент в форматеapp_label.model_name.model_nameрегистронезависим.Поднимает исключение
LookupError, если такое приложение или модель не существует. Поднимает исключениеValueErrorпри вызове с одним аргументом, который не содержит ровно одну точку.
Процесс инициализации
Как загружаются приложения
При запуске Django функция django.setup() отвечает за заполнение регистра приложения.
-
setup()[source] -
Настраивает Джанго, выполняя:
- Загрузку настроек.
- Настройку ведения логов.
- Инициализацию регистра приложения.
Эта функция вызывается автоматически:
- При запуске HTTP-сервера через поддержку WSGI в Джанго.
- При вызове команды управления.
В других случаях ее необходимо вызывать явно, например, в простых скриптах Python.
Регистр приложений инициализируется в три этапа. На каждом этапе Джанго обрабатывает все приложения в порядке INSTALLED_APPS.
-
Сначала Джанго импортирует каждый элемент из
INSTALLED_APPS.Если это класс конфигурации приложения, Джанго импортирует корневой пакет приложения, определяемый его атрибутом
name. Если это пакет Python, Джанго создаёт стандартную конфигурацию приложения.На этом этапе ваш код не должен импортировать модели!
Иными словами, корневые пакеты ваших приложений и модули, которые определяют классы конфигурации ваших приложений, не должны импортировать модели, даже косвенно.
Строго говоря, Джанго позволяет импортировать модели после загрузки конфигурации их приложения. Однако для избежания ненужных ограничений на порядок
INSTALLED_APPSнастоятельно рекомендуется не импортировать модели на этом этапе.После завершения этого этапа API, которые работают с конфигурациями приложений, такие как
get_app_config(), становятся доступными. -
Затем Джанго пытается импортировать подмодуль
modelsкаждого приложения, если он существует.Вы должны определить или импортировать все модели в
models.pyилиmodels/__init__.pyсвоего приложения. В противном случае регистр приложений может не быть полностью заполнен, что может привести к некорректной работе ORM.После завершения этого этапа API, которые работают с моделями, такие как
get_model(), становятся доступными. - Наконец, Джанго выполняет метод
ready()каждой конфигурации приложения.
Отладка приложений
Вот некоторые распространенные проблемы, которые вы можете встретить во время инициализации:
-
AppRegistryNotReadyЭто происходит при импорте конфигурации приложения или модуля моделей, что запускает код, зависящий от реестра приложений.Например,
ugettext()использует реестр приложений для поиска каталогов переводов в приложениях. Для перевода во время импорта вам нуженugettext_lazy()вместо этого. (Использованиеugettext()было бы ошибкой, потому что перевод произошел бы во время импорта, а не при каждом запросе в зависимости от активного языка.)Выполнение запросов к базе данных с помощью ORM во время импорта в модулях моделей также вызовет это исключение. ORM не может работать должным образом, пока все модели не будут доступны.
Еще одной распространённой причиной является
django.contrib.auth.get_user_model(). Используйте настройкуAUTH_USER_MODEL, чтобы сослаться на модель пользователя во время импорта.Это исключение также возникает, если вы забываете вызвать
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/1.8/ref/applications/