Приложения¶
Django содержит реестр установленных приложений, который хранит конфигурацию и обеспечивает интроспекцию. Он также поддерживает список доступных models.
Этот реестр называется просто 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
и wsgi.py
. Пакет проекта часто расширяется, чтобы включить такие вещи, как фиксы, CSS и шаблоны, которые не привязаны к конкретному приложению.
Корневой каталог проекта (тот, который содержит manage.py
) обычно является контейнером для всех приложений проекта, которые не устанавливаются отдельно.
Термин приложение описывает пакет Python, предоставляющий некоторый набор функций. Приложения may be reused в различных проектах.
Приложения включают некоторую комбинацию моделей, представлений, шаблонов, тегов шаблонов, статических файлов, URL-адресов, промежуточного программного обеспечения и т. д. Они обычно подключаются к проектам с помощью настройки 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», то вот как вы предоставите правильное имя для администратора:
# 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
. Кроме этого случая использования, лучше всего избегать использования 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
[исходный код]¶ Объекты конфигурации приложения хранят метаданные для приложения. Некоторые атрибуты могут быть настроены в подклассах
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
. В некоторых ситуациях это необходимо; например, если пакет приложения представляет собой namespace package с несколькими путями.
Атрибуты только для чтения¶
-
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
, подаются только для приложений, имеющих модульpost_migrate
.
Методы¶
-
AppConfig.
get_models
()[исходный код]¶ Возвращает итерабельность
Model
классов для данного приложения.Требуется, чтобы реестр приложений был полностью заполнен.
-
AppConfig.
get_model
(model_name, require_ready=True)[исходный код]¶ Возвращает
Model
с заданнымmodel_name
.model_name
не чувствителен к регистру.Повышает
LookupError
, если такой модели в данном приложении не существует.Требует, чтобы реестр приложений был полностью заполнен, если аргумент
require_ready
не установлен вFalse
.require_ready
ведет себя точно так же, как вapps.get_model()
.
-
AppConfig.
ready
()[исходный код]¶ Подклассы могут переопределить этот метод для выполнения задач инициализации, таких как регистрация сигналов. Он вызывается, как только реестр будет полностью заполнен.
Хотя вы не можете импортировать модели на уровне модуля, где определены классы
AppConfig
, вы можете импортировать их вready()
, используя либо операторimport
, либоget_model()
.Если вы регистрируете
model signals
, вы можете ссылаться на отправителя по его строковой метке вместо использования самого класса модели.Пример:
from django.db.models.signals import pre_save 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
вызывается 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_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
позволяет искать модели while the app registry is being populated, особенно во время второй фазы, когда он импортирует модели. Затемget_model()
имеет тот же эффект, что и импорт модели. Основным вариантом использования является настройка классов моделей с помощью параметров, таких какAUTH_USER_MODEL
.Когда
require_ready
равноFalse
,get_model()
возвращает класс модели, который может быть не полностью функциональным (например, могут отсутствовать обратные аксессоры), пока реестр приложений не будет полностью заполнен. По этой причине лучше всего оставить значениеrequire_ready
по умолчаниюTrue
, когда это возможно.
Процесс инициализации¶
Как загружаются приложения¶
Когда Django запускается, django.setup()
отвечает за заполнение реестра приложений.
-
setup
(set_prefix=True)[исходный код]¶ Настраивает Django на:
- Загрузка настроек.
- Настройка протоколирования.
- Если
set_prefix
равно True, устанавливает префикс скрипта URL resolver в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``q вашего приложения. В противном случае реестр приложения может быть не полностью заполнен в этот момент, что может привести к сбою в работе 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'
.