Spec-Zone.ru › Django 2.2

Система сообщений

В веб-приложениях часто требуется отображать одноразовые уведомления (также известные как «сообщения всплывающего окна») пользователю после обработки формы или другого пользовательского ввода.

Для этого 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.

class storage.cookie.CookieStorage

Этот класс сохраняет данные сообщений в cookie (подписанные секретным хэшем для предотвращения манипуляций) для сохранения уведомлений между запросами. Старые сообщения удаляются, если размер данных cookie превысит 2048 байт.

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 logging. Уровни сообщений позволяют группировать сообщения по типу, чтобы их можно было фильтровать или отображать по-разному в представлениях и шаблонах.

Встроенные уровни, которые можно импортировать из django.contrib.messages напрямую, следующие:

Постоянная Назначение
DEBUG Сообщения, связанные с разработкой, которые будут игнорироваться (или удаляться) в рабочей среде
INFO Информационные сообщения для пользователя
SUCCESS Действие было выполнено успешно, например, «Ваш профиль успешно обновлён»
WARNING Ошибка не произошла, но может произойти
ERROR Действие не было выполнено успешно или произошла какая-то другая ошибка

Настройка MESSAGE_LEVEL может быть использована для изменения минимального уровня записи (или может быть изменена в рамках запроса). Попытки добавить сообщения уровня ниже этого будут проигнорированы.

Теги сообщений

Теги сообщений — строковое представление уровня сообщения плюс любые дополнительные теги, добавленные непосредственно в представлении (см. Добавление дополнительных тегов сообщений ниже для получения дополнительных подробностей). Теги хранятся в строке и разделены пробелами. Обычно теги сообщений используются как классы CSS для настройки стиля сообщений в зависимости от типа сообщения. По умолчанию для каждого уровня есть один тег, который является строчной версией собственного константы:

Константа уровня Тег
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, где каждое окно/вкладка будет иметь собственный контекст просмотра.

Настройки

Несколько настроек позволяют контролировать поведение сообщений:

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS

Для бэкендов, использующих файлы cookie, настройки для файлов cookie берутся из настроек файлов cookie сеанса:

  • SESSION_COOKIE_DOMAIN
  • SESSION_COOKIE_SECURE
  • SESSION_COOKIE_HTTPONLY

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/ref/contrib/messages/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API