Spec-Zone.ru › Django 3.1

Система сообщений

В веб-приложениях часто требуется отображать одноразовые уведомления (также известные как «сообщения всплывающего окна») пользователю после обработки формы или другого типа ввода.

Для этого Django предоставляет полную поддержку хранения сообщений на основе файлов cookie и сеансов для анонимных и авторизованных пользователей. Система сообщений позволяет временно хранить сообщения в одном запросе и извлекать их для отображения в последующем запросе (обычно в следующем). Каждое сообщение помечено определенным level, определяющим его приоритет (например, info, warning, или error).

Включение системы сообщений

Система сообщений реализована через класс обработчика среднего уровня и соответствующий процессор контекста.

По умолчанию settings.py созданный django-admin startproject уже содержит все необходимые настройки для включения функциональности сообщений:

  • 'django.contrib.messages' находится в INSTALLED_APPS.
  • MIDDLEWARE содержит 'django.contrib.sessions.middleware.SessionMiddleware' и 'django.contrib.messages.middleware.MessageMiddleware'.

    По умолчанию хранилище использует сеансы. Поэтому SessionMiddleware должно быть включено и находиться перед MessageMiddleware в MIDDLEWARE.

  • Параметр 'context_processors' хранилища DjangoTemplates, определенного в настройке TEMPLATES, содержит 'django.contrib.messages.context_processors.messages'.

Если вы не хотите использовать систему сообщений, вы можете удалить 'django.contrib.messages' из INSTALLED_APPS, строку MessageMiddleware из MIDDLEWARE и процессор контекста messages из TEMPLATES.

Настройка движка сообщений

Хранилища сообщений

Система сообщений может использовать различные хранилища для временного хранения сообщений.

Django предоставляет три встроенных класса хранилищ в django.contrib.messages:

class storage.session.SessionStorage

Этот класс хранит все сообщения внутри сеанса запроса. Поэтому он требует приложения Django contrib.sessions.

class storage.cookie.CookieStorage

Этот класс сохраняет данные сообщения в файле cookie (подписанном секретным хэшем для предотвращения манипуляций), чтобы сохранять уведомления между запросами. Старые сообщения удаляются, если размер данных cookie превысит 2048 байт.

class storage.fallback.FallbackStorage

Этот класс сначала использует CookieStorage, а затем переходит к использованию SessionStorage для сообщений, которые не поместились в один cookie. Он также требует приложения Django contrib.sessions.

Это поведение позволяет избежать записи в сеанс, когда это возможно. Оно должно обеспечивать наилучшую производительность в общем случае.

FallbackStorage — это хранилище по умолчанию. Если оно не подходит, вы можете выбрать другое хранилище, задав MESSAGE_STORAGE его полным импортным путем, например:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
class storage.base.BaseStorage

Чтобы написать свой собственный класс хранилища, унаследуйте от класса BaseStorage в django.contrib.messages.storage.base и реализуйте методы _get и _store.

Уровни сообщений

Система сообщений основана на конфигурируемой архитектуре уровней, аналогичной модулю Python logging. Уровни сообщений позволяют группировать сообщения по типу, чтобы их можно было фильтровать или отображать по-разному в представлениях и шаблонах.

Встроенные уровни, которые можно импортировать из django.contrib.messages напрямую, это:

Константа Назначение
DEBUG Сообщения, связанные с разработкой, которые будут игнорироваться (или удаляться) при развертывании в продакшене
INFO Информационные сообщения для пользователя
SUCCESS Действие выполнено успешно, например, «Ваш профиль был успешно обновлен»
WARNING Ошибка еще не произошла, но может произойти
ERROR Действие не было выполнено успешно или произошла другая ошибка

Настройка MESSAGE_LEVEL может использоваться для изменения минимального уровня записи (или его можно изменить для каждого запроса). Попытки добавить сообщения уровня ниже этого будут игнорироваться.

Теги сообщений

Теги сообщений — это строковое представление уровня сообщения плюс любые дополнительные теги, добавленные непосредственно в представлении (подробнее см. Добавление дополнительных тегов сообщений ниже). Теги хранятся в строке и разделяются пробелами. Обычно теги сообщений используются как классы CSS для настройки стиля сообщения в зависимости от типа сообщения. По умолчанию каждый уровень имеет один тег, являющийся строчной версией своей константы:

Константа уровня Тег
DEBUG debug
INFO info
SUCCESS success
WARNING warning
ERROR error

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

from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
    messages.INFO: '',
    50: 'critical',
}

Использование сообщений в представлениях и шаблонах

add_message(request, level, message, extra_tags='', fail_silently=False)

Добавление сообщения

Для добавления сообщения вызовите:

from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')

Некоторые сокращенные методы предоставляют стандартный способ добавления сообщений с часто используемыми тегами (которые обычно представляются HTML-классами для сообщения):

messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')

Отображение сообщений

get_messages(request)

В вашем шаблоне используйте что-то вроде:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Если вы используете процессор контекста, ваш шаблон должен быть рендеризирован с RequestContext. В противном случае убедитесь, что messages доступен в контексте шаблона.

Даже если вы знаете, что сообщение только одно, вы все равно должны итерировать последовательность messages, иначе хранилище сообщений не будет очищено для следующего запроса.

Процессор контекста также предоставляет переменную DEFAULT_MESSAGE_LEVELS, которая является отображением имен уровней сообщений в их числовом значении:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
        {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}Important: {% endif %}
        {{ message }}
    </li>
    {% endfor %}
</ul>
{% endif %}

За пределами шаблонов вы можете использовать get_messages():

from django.contrib.messages import get_messages

storage = get_messages(request)
for message in storage:
    do_something_with_the_message(message)

Например, вы можете извлечь все сообщения, чтобы вернуть их в JSONResponseMixin вместо TemplateResponseMixin.

get_messages() вернет экземпляр настроенного хранилища сообщений.

Класс Message

class storage.base.Message

Когда вы перебираете список сообщений в шаблоне, вы получаете экземпляры класса Message. У них всего несколько атрибутов:

  • message: фактический текст сообщения.
  • level: целое число, описывающее тип сообщения (см. раздел уровни сообщений выше).
  • tags: строка, объединяющая все теги сообщения (extra_tags и level_tag) разделённые пробелами.
  • extra_tags: строка, содержащая пользовательские теги для этого сообщения, разделённые пробелами. По умолчанию пустая.
  • level_tag: строковое представление уровня. По умолчанию это строчная версия имени соответствующей константы, но это можно изменить, если нужно, с помощью настройки MESSAGE_TAGS.

Создание пользовательских уровней сообщений

Уровни сообщений — это не более чем целые числа, поэтому вы можете определить свои собственные константы уровня и использовать их для создания более настраиваемой обратной связи с пользователем, например:

CRITICAL = 50

def my_view(request):
    messages.add_message(request, CRITICAL, 'A serious error occurred.')

При создании пользовательских уровней сообщений следует быть осторожным, чтобы не перегружать существующие уровни. Значения для встроенных уровней следующие:

Константа уровня Значение
DEBUG 10
INFO 20
SUCCESS 25
WARNING 30
ERROR 40

Если вам нужно идентифицировать пользовательские уровни в вашем HTML или CSS, вам нужно предоставить отображение через настройку MESSAGE_TAGS.

Примечание

Если вы создаёте повторно используемое приложение, рекомендуется использовать только встроенные уровни сообщений, а не полагаться на какие-либо пользовательские уровни.

Изменение минимального уровня записи на запрос

Минимальный уровень записи можно установить на запрос с помощью метода set_level.

from django.contrib import messages

# Change the messages level to ensure the debug message is added.
messages.set_level(request, messages.DEBUG)
messages.debug(request, 'Test message...')

# In another request, record only messages with a level of WARNING and higher
messages.set_level(request, messages.WARNING)
messages.success(request, 'Your profile was updated.') # ignored
messages.warning(request, 'Your account is about to expire.') # recorded

# Set the messages level back to default.
messages.set_level(request, None)

Аналогично, текущий эффективный уровень можно получить с помощью get_level.

from django.contrib import messages
current_level = messages.get_level(request)

Дополнительную информацию о том, как работает минимальный уровень записи, см. в разделе Уровни сообщений выше.

Добавление дополнительных меток сообщений

Для более прямого управления метками сообщений вы можете необязательно указать строку с дополнительными метками для любого из методов добавления:

messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')

Дополнительные метки добавляются перед стандартной меткой для данного уровня и разделены пробелами.

Безмолвная обработка ошибок при отключении фреймворка сообщений

Если вы пишете повторно используемое приложение (или другой фрагмент кода) и хотите включить функциональность сообщений, но не хотите, чтобы ваши пользователи были обязаны ее активировать, вы можете передать дополнительный ключевой аргумент fail_silently=True любому из методов семейства add_message. Например:

messages.add_message(
    request, messages.SUCCESS, 'Profile details updated.',
    fail_silently=True,
)
messages.info(request, 'Hello world.', fail_silently=True)

Примечание

Установка fail_silently=True только скрывает MessageFailure, которые в противном случае возникают при отключенном фреймворке сообщений и попытке использовать один из методов семейства add_message. Это не скрывает сбои, которые могут возникнуть по другим причинам.

Добавление сообщений в представления на основе классов

class views.SuccessMessageMixin

Добавляет атрибут сообщения об успехе к классам на основе FormView.

get_success_message(cleaned_data)

cleaned_data — это очищенные данные формы, используемые для форматирования строк.

Пример views.py:

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(SuccessMessageMixin, CreateView):
    model = Author
    success_url = '/success/'
    success_message = "%(name)s was created successfully"

Очищенные данные из form доступны для интерполяции строк с помощью синтаксиса %(field_name)s. Для ModelForms, если вам нужен доступ к полям сохранённого object, переопределите метод get_success_message().

Пример views.py для ModelForms:

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView
from myapp.models import ComplicatedModel

class ComplicatedCreate(SuccessMessageMixin, CreateView):
    model = ComplicatedModel
    success_url = '/success/'
    success_message = "%(calculated_field)s was created successfully"

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            calculated_field=self.object.calculated_field,
        )

Срок действия сообщений

Сообщения помечаются для удаления при итерации экземпляра хранилища (и удаляются при обработке ответа).

Чтобы предотвратить удаление сообщений, можно установить хранилище сообщений в False после итерации:

storage = messages.get_messages(request)
for message in storage:
    do_something_with(message)
storage.used = False

Поведение параллельных запросов

Из-за того, как работают куки (и, следовательно, сессии), поведение любых бэкэндов, использующих куки или сессии, не определено, когда один и тот же клиент выполняет несколько запросов, которые устанавливают или получают сообщения параллельно. Например, если клиент инициирует запрос, создающий сообщение в одном окне (или вкладке), а затем другой, который извлекает любые неитерированные сообщения в другом окне, прежде чем первое окно перенаправится, сообщение может появиться во втором окне вместо первого окна, где оно ожидалось.

Короче говоря, когда участвуют несколько одновременных запросов от одного клиента, сообщения не гарантируются для доставки в то же окно, которое их создало, ни, в некоторых случаях, вообще. Обратите внимание, что обычно это не проблема в большинстве приложений и перестанет быть проблемой в HTML5, где каждое окно/вкладка будет иметь свой контекст просмотра.

Настройки

Несколько настроек предоставляют вам управление поведением сообщений:

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS

Для бэкэндов, использующих куки, настройки куки берутся из настроек куки сессии:

  • SESSION_COOKIE_DOMAIN
  • SESSION_COOKIE_SECURE
  • SESSION_COOKIE_HTTPONLY

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

Spec-Zone.ru

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