Spec-Zone.ru › Django 5.0

Приложения

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",
    ...,
]

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

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

# 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

Объекты конфигурации приложения хранят метаданные для приложения. Некоторые атрибуты можно настроить в подклассах 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. В некоторых ситуациях это необходимо; например, если пакет приложения является пространством имён с несколькими путями.

AppConfig.default

Установите этот атрибут в False для предотвращения автоматического выбора Django класса конфигурации. Это полезно, когда apps.py определяет только один подкласс AppConfig, но вы не хотите, чтобы Django его использовал по умолчанию.

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

По умолчанию этот атрибут не установлен.

END_OF_DOCUMENT_MARKER
AppConfig.default_auto_field

Неявной тип первичного ключа, который добавляется к моделям в этом приложении. Вы можете использовать его, чтобы сохранить 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)

Возвращает итерируемый список классов 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.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 в whenever possible.

Процесс загрузки приложений

Как загружаются приложения

При запуске Django, метод django.setup() отвечает за заполнение реестра приложений.

setup(set_prefix=True) [source]

Настраивает Django следующим образом:

  • Загружает настройки.
  • Настраивает логирование.
  • Если set_prefix равно True, устанавливает префикс скрипта обработчика URL на FORCE_SCRIPT_NAME, если он определен, или на / в противном случае.
  • Инициализирует реестр приложений.

Эта функция вызывается автоматически:

  • При запуске HTTP-сервера с помощью поддержки ASGI или WSGI Django.
  • При вызове команды управления.

В других случаях, например, в обычных скриптах 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.0/ref/applications/

Spec-Zone.ru

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