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