Система сообщений
В веб-приложениях часто требуется отображать одноразовые уведомления (также известные как «сообщения всплывающего окна») пользователю после обработки формы или другого ввода.
Для этого 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 -
Этот класс хранит данные сообщения в cookie (подписанном секретным хэшем, чтобы предотвратить манипуляции), для сохранения уведомлений между запросами. Старые сообщения удаляются, если размер cookie данных превысит 2048 байт.
-
class storage.fallback.FallbackStorage -
Этот класс сначала использует
CookieStorage, а затем переходит к использованиюSessionStorageдля сообщений, которые не помещаются в одно cookie. Он также требует модуля 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)
Добавление сообщения
Для добавления сообщения вызовите:
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 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 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
Поведение параллельных запросов
Из-за того, как работают cookie (и, следовательно, сессии), поведение любых бэкендов, использующих cookie или сессии, не определено, когда один и тот же клиент выполняет несколько запросов, которые устанавливают или получают сообщения параллельно. Например, если клиент инициирует запрос, создающий сообщение в одном окне (или вкладке), а затем другой, извлекающий любые неитерированные сообщения в другом окне, до перенаправления первого окна, сообщение может появиться во втором окне вместо первого, где ожидалось.
Короче говоря, при одновременных запросах от одного и того же клиента сообщения не гарантируется, что будут доставлены тому же окну, которое их создало, или, в некоторых случаях, вообще. Обратите внимание, что это, как правило, не проблема в большинстве приложений и перестанет быть проблемой в HTML5, где каждое окно/вкладка будет иметь свой собственный контекст просмотра.
Настройки
Несколько настроек позволяют управлять поведением сообщений:
Для бэкендов, использующих cookie, настройки cookie берутся из настроек cookie сессии:
Тестирование
Этот модуль предоставляет настраиваемый метод проверки утверждений для тестирования сообщений, прикрепленных к HttpResponse.
Чтобы воспользоваться этим утверждением, добавьте MessagesTestMixin в иерархию классов:
from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase
class MsgTestCase(MessagesTestMixin, TestCase):
pass
Затем унаследуйте от MsgTestCase в своих тестах.
-
MessagesTestMixin.assertMessages(response, expected_messages, ordered=True) -
Проверяет, что
messages, добавленные вresponse, соответствуютexpected_messages.expected_messages— это список объектовMessage.По умолчанию сравнение зависит от порядка. Вы можете отключить это, установив аргумент
orderedвFalse.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/ref/contrib/messages/