Приложения¶
Django содержит реестр установленных приложений, который содержит текущие настройки и предоставляет интроспекцию. Также предоставляет список доступных моделей.
This registry is called apps and it’s available in
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) обычно является контейнером для всех приложений проекта, которые не устанавливаются отдельно.
Термин application используется для пакета Python, который предоставляет определенный функционал. Приложения могут повторно использоваться в различных проектах.
Приложения содержат набор моделей, представлений, шаблонов, шаблонных тегов, статических файлов, URL-ов, мидлваров, и прочее. Они добавляются в проект через настройку INSTALLED_APPS, подключение в URLconfs, настройку MIDDLEWARE_CLASSES, или наследование шаблонов.
Важно помнить, что приложение 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',
...
]
Для пользователей приложений¶
Если вы используете приложение с «Rock ’n’ roll» в проекте, который называется anthology, и хотите заменить на «Gypsy jazz», вы можете добавить свой класс настроек:
# 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¶
Объект конфигурации приложения содержит метаданные о приложении. Некоторые атрибуты можно указать в классе наследнике
AppConfig. Некоторые определены Django и доступны только для чтения.
Настраиваемые атрибуты¶
- AppConfig.name¶
Полный Python путь для импорта приложения, например
'django.contrib.admin'.Этот атрибут указывает к какому приложению относится класс настроек. Должен указываться во всех классах наследниках
AppConfig.Должен быть уникальным для проекта.
- AppConfig.label¶
Короткое название(метка) приложения, например
'admin'Этот атрибут позволяет поменять метку приложения, если два приложения используют по умолчанию одинаковые метки. По умолчанию метка равна последней части значения
name. Метка должна быть правильным идентификатором Python.Должен быть уникальным для проекта.
- AppConfig.verbose_name¶
Читабельное название приложения, например «Administration».
По умолчанию равен
label.title().
- AppConfig.path¶
Путь в файловой системе к каталогу с приложением, например
'/usr/lib/python3.4/dist-packages/django/contrib/admin'.В большинстве случае Django может автоматически определить и установить это значение, но вы можете переопределить его в классе наследнике
AppConfig. Это может понадобиться в некоторых случаях, например, если пакет приложения является namespace-пакетом и расположен в нескольких каталогах.
- AppConfig.default¶
- New in Django 3.2.
Установите для этого атрибута значение «False», чтобы Django не мог автоматически выбирать класс конфигурации. Это полезно, когда
apps.pyопределяет только один подклассAppConfig, но вы не хотите, чтобы Django использовал его по умолчанию.Установите для этого атрибута значение True, чтобы Django автоматически выбирал класс конфигурации. Это полезно, когда
apps.pyопределяет более одного подклассаAppConfigи вы хотите, чтобы Django использовал один из них по умолчанию.По умолчанию этот атрибут не установлен.
- AppConfig.default_auto_field¶
- New in Django 3.2.
Тип неявного первичного ключа, добавляемый в модели в этом приложении. Вы можете использовать это, чтобы сохранить
AutoFieldв качестве типа первичного ключа для сторонних приложений.По умолчанию это значение
DEFAULT_AUTO_FIELD.
Неизменяемые атрибуты¶
- 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()¶
Возвращает итератор по классам
Modelдля текущего приложения.Требуется, чтобы реестр приложений был полностью заполнен.
- AppConfig.get_model(model_name, require_ready=True)¶
Возвращает
Modelдля переданногоmodel_name. ВызываетLookupError, если модель не существует.model_nameрегистро-независимое значение.Вызывает
LookupError, если в этом приложении такой модели не существует.Требует, чтобы реестр приложения был полностью заполнен, если только для аргумента
require_readyне установлено значениеFalse.require_readyведет себя точно так же, как вapps.get_model().
- AppConfig.ready()¶
Класс наследник может переопределить этот метод, чтобы выполнить инициализацию приложения, например зарегистрировать сигналы. Вызывает, когда реестр приложений будет полностью инициализирован и все приложения будут добавлены.
Хотя вы не можете импортировать модели на уровне модуля, где определены классы
AppConfig, вы можете импортировать их вready(), используя либо операторimport, либоget_model().Если вы регистрируете сигналы модели <django.db.models.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()будет вызываться при каждом запуске команды Django. Например, хотя настройка тестовой базы данных отделена от рабочих настроек проекта,manage.py testвыполнила бы запросы на рабочей базе данных!Примечание
In the usual initialization process, the
readymethod is only called once by Django. But in some corner cases, particularly in tests which are fiddling with installed applications,readymight be called more than once. In that case, either write idempotent methods, or put a flag on yourAppConfigclasses to prevent re-running code which should be executed exactly one time.
Namespace-пакеты приложений (Python 3.3+)¶
Python версии 3.3 и выше поддерживает Python пакеты без файла __init__.py. Эти пакеты называют «namespace-пакетами» и могут находится в нескольких каталогах в sys.path (смотрите PEP 420).
Django приложениям необходим один основной путь в файловой системе, где Django (в зависимости от настроек) будет искать шаблоны, статические файлы, и прочее. Таким образом, namespace-пакеты могут быть приложениями Django только при следующих условиях:
Namespace-пакет содержит один каталог (то есть не разделен на несколько каталогов)
Используется класс
AppConfig, указывающий вpathодин абсолютный путь к каталогу, который Django будет использовать как каталог приложения.
Если ни одно из этих условий не соблюдено, Django вызовет исключение ImproperlyConfigured.
Реестр приложений¶
- apps¶
Реестр приложений предоставляет следующий публичный API. Методы, которые не описаны здесь, являются приватными и могут изменяться в будущем без предупреждений.
- apps.ready¶
Булев атрибут, который устанавливается в
True, когда реестр полностью проинициализирован.
- 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.setup() отвечает за заполнение реестра приложений при запуске Django.
- setup(set_prefix=True)¶
Настраивает Django, выполняя следующие действия:
Загрузка настроек.
Настройка логирования.
Если
set_prefixимеет значение True, установка префикса сценария преобразователя URL-адресов вFORCE_SCRIPT_NAME, если он определен, или/в противном случае.Инициализация реестра приложений.
Эта функция вызывается автоматически:
When running an HTTP server via Django’s WSGI support.
При выполнении команды 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. Вызывается при импорте настроек приложения или модуля моделей, код которых использует реестр приложений.Например,
ugettext()использует реестр приложений для поиска каталогов с файлами локализации. Для локализации на этапе импорта используйтеugettext_lazy(). (Использованиеugettext()приведет к багу, т.к. перевод будет выполнен на момент импорта, а не для каждого запрос с учетом активной локалид.)Выполнение запросов к базе данных с помощью ORM в процессе импорта модуля моделей вызовет исключение. ORM не может работать, пока все модели не будут загружены.
Эта ошибка также вызывается, если
django.setup()не был вызван в Python скрипте.ImportError: cannot import name .... Ошибка вызывается при циклических импортах.Для устранения таких проблем необходимо минимизировать зависимости между модулями моделей и в процессе импорта выполнять минимум действий. Чтобы избежать выполнения кода на этапе импорта, вынесите его в функцию, которая умеет кэшировать результат. Затем вызовите функции при необходимости. Такая концепция называется «ленивое выполнение».
django.contrib.adminавтоматически выполняет регистрацию модулейadminустановленных приложений. Чтобы отключить это, укажите вINSTALLED_APPS'django.contrib.admin.apps.SimpleAdminConfig'вместо'django.contrib.admin'.