Система сообщений
В веб-приложениях часто требуется отобразить одноразовое уведомление (также известное как «сообщение всплывающей подсказки») пользователю после обработки формы или других типов пользовательского ввода.
Для этого Django предоставляет полную поддержку хранения сообщений на основе куки и сеанса для анонимных и авторизованных пользователей. Система сообщений позволяет временно хранить сообщения в одном запросе и извлекать их для отображения в последующем запросе (обычно в следующем). Каждое сообщение помечено определённым 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 -
Этот класс сохраняет данные сообщения в куки (зашифрованных секретным хэшем для предотвращения подделки), чтобы сохранять уведомления между запросами. Старые сообщения удаляются, если размер данных куки превысит 2048 байт.
-
class storage.fallback.FallbackStorage -
Этот класс сначала использует
CookieStorage, а затем переходит к использованиюSessionStorageдля сообщений, которые не поместились в одной куки. Он также требует приложения Djangocontrib.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 может использоваться для изменения минимального записываемого уровня (или его можно изменить на уровне запроса). Попытки добавить сообщения уровня ниже этого будут игнорироваться.
Теги сообщений
| Константа уровня | Тег |
|---|---|
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)[source]
Добавление сообщения
Для добавления сообщения вызовите:
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)[source]
В вашем шаблоне используйте что-то вроде:
{% 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 family. Например:
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 family. Она не скрывает сбои, которые могут произойти по другим причинам.
Добавление сообщений в представления на основе классов
-
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 AuthorCreateView(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 ComplicatedCreateView(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, где каждое окно/вкладка будет иметь свой собственный контекст просмотра.
Настройки
Несколько настроек предоставляют вам контроль над поведением сообщений:
Для бэкэндов, использующих куки, настройки куки берутся из настроек куки сессии:
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.1/ref/contrib/messages/