Spec-Zone.ru › Django 2.2

Приложения

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, и wsgi.py. Пакет проекта часто расширяется, чтобы включать такие вещи, как фикстуры, CSS и шаблоны, которые не привязаны к конкретному приложению.

Корневая директория проекта (та, которая содержит manage.py) обычно служит контейнером для всех приложений проекта, которые не установлены отдельно.

Термин приложение описывает пакет Python, который предоставляет набор функций. Приложения могут быть повторно использованы в различных проектах.

Приложения включают в себя некоторую комбинацию моделей, представлений, шаблонов, тегов шаблонов, статических файлов, URL-адресов, middleware и т. д. Они обычно подключаются к проектам с помощью настройки INSTALLED_APPS и необязательно с помощью других механизмов, таких как URLconf, настройки 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 [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/pythonX.Y/dist-packages/django/contrib/admin'.

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

Атрибуты только для чтения

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

setup(set_prefix=True) [source]

Настраивает Джанго следующим образом:

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

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

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

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

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

END_OF_DOCUMENT_MARKER
  1. Первая стадия в Django — импорт каждого элемента из INSTALLED_APPS.

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

    На этой стадии ваш код не должен импортировать модели!

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

    Строго говоря, 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'.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/ref/applications/

Spec-Zone.ru

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