Spec-Zone.ru › Django 5.1

Приложения

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 и, по желанию, другими механизмами, такими как URLconf, настройкой 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",
    ...,
]

Для авторов приложений

Если вы создаёте подключаемое приложение под названием «Рок-н-ролл», вот как вы можете предоставить надлежащее имя для администрирования:

# rock_n_roll/apps.py

from django.apps import AppConfig


class RockNRollConfig(AppConfig):
    name = "rock_n_roll"
    verbose_name = "Rock ’n’ roll"

RockNRollConfig будет загружен автоматически, когда INSTALLED_APPS содержит 'rock_n_roll'. Если вам нужно это предотвратить, установите default в False в определении класса.

Вы можете предоставить несколько подклассов AppConfig с различным поведением. Чтобы указать Django, какой из них использовать по умолчанию, установите default в True в его определении. Если пользователи хотят выбрать нестандартную конфигурацию, они должны заменить 'rock_n_roll' полным именем этого конкретного класса в настройке INSTALLED_APPS.

Атрибут AppConfig.name сообщает Django, к какому приложению относится эта конфигурация. Вы можете определить любые другие атрибуты, описанные в справочнике API AppConfig.

Подклассы AppConfig могут быть определены где угодно. Конвенция apps.py просто позволяет Django загружать их автоматически, когда INSTALLED_APPS содержит путь к модулю приложения, а не к классу конфигурации.

Примечание

Если ваш код импортирует реестр приложений в модуле __init__.py приложения, имя apps будет конфликтовать с подмодулем apps. Лучшей практикой является перемещение этого кода в подмодуль и его импорт. Обходным путём является импорт реестра под другим именем:

from django.apps import apps as django_apps

Для пользователей приложений

Если вы используете «Рок-н-ролл» в проекте под названием 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(), методы менеджеров и т. д.), а также запросы SQL через django.db.connection. Ваш метод ready() будет выполняться во время запуска каждой команды управления. Например, даже если конфигурация тестовой базы данных отличается от конфигурации производственной среды, manage.py test всё равно будет выполнять некоторые запросы к вашей **производственной** базе данных!

Примечание

В обычном процессе инициализации метод ready вызывается Django только один раз. Но в некоторых особых случаях, особенно в тестах, которые изменяют установленные приложения, ready может быть вызван более одного раза. В таком случае либо напишите идемпотентные методы, либо поместите флаг в ваши классы AppConfig для предотвращения повторного выполнения кода, который должен быть выполнен ровно один раз.

Пакеты имен как приложения

Пакеты Python без файла __init__.py известны как «пространственные пакеты» и могут быть распределены по нескольким каталогам в разных местах на sys.path (см. PEP 420).

Приложения Django требуют одного базового пути файловой системы, где Django (в зависимости от конфигурации) будет искать шаблоны, статические ресурсы и т. д. Таким образом, пространственные пакеты могут быть приложениями Django только в том случае, если выполняется одно из следующих условий:

  1. Пространственный пакет на самом деле имеет только одно расположение (т. е. не распределяется по более чем одному каталогу).
  2. Класс 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-сервера через поддержку Django ASGI или WSGI.
  • При вызове командной утилиты управления.

В других случаях её необходимо вызывать явно, например, в обычных Python-скриптах.

Изменено в Django 5.0:

Вызывает RuntimeWarning при взаимодействии приложений с базой данных до полного заполнения регистра приложений.

Регистр приложений инициализируется в три этапа. На каждом этапе Django обрабатывает все приложения в порядке INSTALLED_APPS.

  1. Сначала Django импортирует каждый элемент в INSTALLED_APPS.

    Если это класс конфигурации приложения, Django импортирует корневой пакет приложения, определённый его атрибутом name. Если это Python-пакет, Django ищет конфигурацию приложения в подмодуле apps.py, или же создаёт конфигурацию приложения по умолчанию.

    На этом этапе не следует импортировать модели!

    Другими словами, корневые пакеты ваших приложений и модули, определяющие классы конфигурации ваших приложений, не должны импортировать модели, даже косвенно.

    Строго говоря, Django позволяет импортировать модели после загрузки их конфигурации приложения. Однако, чтобы избежать ненужных ограничений на порядок INSTALLED_APPS, настоятельно рекомендуется не импортировать модели на этом этапе.

    После завершения этого этапа API, работающие с конфигурациями приложений, такие как get_app_config(), становятся доступными.

  2. Затем Django пытается импортировать подмодуль models каждого приложения, если он есть.

    Вы должны определить или импортировать все модели в подмодуле models.py или models/__init__.py вашего приложения. В противном случае регистр приложений может не быть полностью заполнен на этом этапе, что может привести к сбоям в работе ORM.

    После завершения этого этапа API, работающие с моделями, такие как get_model(), становятся доступными.

  3. Наконец, 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.1/ref/applications/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API