Система сообщений
В веб-приложениях часто требуется отобразить одноразовое уведомление (также известное как «сообщение-всплышка») пользователю после обработки формы или другого типа пользовательского ввода.
Для этого 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.
-
Этот класс сохраняет данные сообщения в куки (подписанные секретным хэшем для предотвращения манипуляций), чтобы уведомления сохранялись между запросами. Старые сообщения удаляются, если размер данных куки превысит 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 семейства. Например:
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, где каждое окно/вкладка будет иметь свой собственный контекст просмотра.
Настройки
Несколько настроек позволяют управлять поведением сообщений:
Для бэкэндов, использующих куки, настройки куки берутся из настроек куки сессии:
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/ref/contrib/messages/