Структура сообщений¶
Довольно часто в веб-приложениях вам необходимо отобразить пользователю одноразовое уведомление (также известное как «мгновенное сообщение») после обработки формы или некоторых других типов пользовательского ввода.
Для этого Django обеспечивает полную поддержку обмена сообщениями на основе файлов cookie и сеансов как для анонимных, так и для аутентифицированных пользователей. Фреймворк сообщений позволяет временно хранить сообщения в одном запросе и извлекать их для отображения в последующем запросе (обычно следующем). Каждое сообщение помечается определенным «уровнем», который определяет его приоритет (например, «информация», «предупреждение» или «ошибка»).
Включение сообщений¶
Сообщения реализуются через класс промежуточного программного обеспечения и соответствующий контекстный процессор.
Файл settings.py по умолчанию, созданный django-admin startproject, уже содержит все настройки, необходимые для включения функциональности сообщений:
'django.contrib.messages'находится вINSTALLED_APPS.MIDDLEWAREсодержит'django.contrib.sessions.middleware.SessionMiddleware'и'django.contrib.messages.middleware.MessageMiddleware'.Базовая часть хранилища по умолчанию <message-storage-backends>` использует сессии. Вот почему SessionMiddleware должен быть включен и появляться перед MessageMiddleware в
MIDDLEWARE.Опция
'context_processors'бэкендаDjangoTemplates, определенная в вашем параметреTEMPLATES, содержит'django.contrib.messages.context_processors.messages'.
Если вы не хотите использовать сообщения, вы можете удалить 'django.contrib.messages'` из вашего :setting:`INSTALLED_APPS`, строку ``MessageMiddleware из MIDDLEWARE и контекстного процессора messages из TEMPLATES.
Настройка механизма сообщений¶
Серверные части хранилища¶
Платформа сообщений может использовать разные серверные части для хранения временных сообщений.
Django предоставляет три встроенных класса хранения в django.contrib.messages:
- class storage.session.SessionStorage¶
Этот класс хранит все сообщения внутри сеанса запроса. Поэтому для этого требуется приложение Django
contrib.sessions.
- class storage.cookie.CookieStorage¶
Этот класс хранит данные сообщения в файле cookie (подписанном секретным хешем для предотвращения манипуляций) для сохранения уведомлений между запросами. Старые сообщения удаляются, если размер данных cookie превышает 2048 байт.
Changed in Django 3.2:Messages format was changed to the RFC 6265 compliant format.
- 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. Уровни сообщений позволяют группировать сообщения по типу, чтобы их можно было фильтровать или по-разному отображать в представлениях и шаблонах.
Встроенные уровни, которые можно импортировать напрямую из django.contrib.messages:
Постоянный |
Цель |
|---|---|
|
Сообщения, связанные с разработкой, которые будут игнорироваться (или удаляться) при производственном развертывании. |
|
Информационные сообщения для пользователя |
|
Действие было успешным, например. «Ваш профиль успешно обновлен» |
|
Сбой не произошел, но может быть неизбежным |
|
Действие было не успешным или произошел какой-либо другой сбой |
Параметр MESSAGE_LEVEL можно использовать для изменения минимального записываемого уровня (или его можно изменять по запросу). Попытки добавить сообщения уровня ниже этого будут игнорироваться.
Использование сообщений в представлениях и шаблонах¶
- 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)¶
In your template, use something like:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
Если вы используете контекстный процессор, ваш шаблон должен отображаться с помощью RequestContext. В противном случае убедитесь, что сообщения доступны для контекста шаблона.
Даже если вы знаете, что есть только одно сообщение, вам все равно следует перебирать последовательность «сообщений», потому что в противном случае хранилище сообщений не будет очищено для следующего запроса.
The context processor also provides a DEFAULT_MESSAGE_LEVELS variable which
is a mapping of the message level names to their numeric value:
{% 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() вернет экземпляр настроенного бэкэнда хранилища.
Класс Сообщение¶
- class storage.base.Message¶
Когда вы перебираете список сообщений в шаблоне, вы получаете экземпляры класса Message. У них есть всего несколько атрибутов:
message: фактический текст сообщения.уровень: целое число, описывающее тип сообщения (см. раздел ``уровни сообщений`_ выше).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.')
При создании пользовательских уровней сообщений следует соблюдать осторожность, чтобы не перегружать существующие уровни. Значения встроенных уровней:
Константа уровня |
Значение |
|---|---|
|
10 |
|
20 |
|
25 |
|
30 |
|
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)
Дополнительную информацию о том, как работает минимальный записываемый уровень, см. в разделе «Уровни сообщений» выше.
Сбой молча, когда структура сообщений отключена¶
Если вы пишете повторно используемое приложение (или другой фрагмент кода) и хотите включить функцию обмена сообщениями, но не хотите требовать от пользователей включать ее, если они этого не хотят, вы можете передать дополнительный аргумент ключевого слова fail_silily=True в любой из методов add_message. Например:
messages.add_message(
request, messages.SUCCESS, 'Profile details updated.',
fail_silently=True,
)
messages.info(request, 'Hello world.', fail_silently=True)
Примечание
Установка fail_silly=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"
Очищенные данные из формы доступны для строковой интерполяции с использованием синтаксиса %(имя_поля)s. Для ModelForms, если вам нужен доступ к полям из сохраненного объекта, переопределите метод get_success_message().
Пример view.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, где каждое окно/вкладка будет иметь свой собственный контекст просмотра.
Настройки¶
Несколько settings дают вам контроль над поведением сообщений:
Для серверов, использующих файлы cookie, настройки файла cookie берутся из настроек файла cookie сеанса: