Spec-Zone.ru › Django 2.1

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

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

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

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

class storage.fallback.FallbackStorage

Этот класс сначала использует CookieStorage, а затем использует SessionStorage для сообщений, которые не поместились в одну куки. Он также требует приложения 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

Поведение параллельных запросов

Из-за того, как работают куки (и, следовательно, сессии), поведение любых бэкэндов, использующих куки или сессии, не определено, когда один и тот же клиент выполняет несколько запросов, которые устанавливают или получают сообщения параллельно. Например, если клиент инициирует запрос, который создаёт сообщение в одном окне (или вкладке), а затем другой запрос, который извлекает любые неитерированные сообщения в другом окне, прежде чем первое окно перенаправится, сообщение может появиться во втором окне вместо первого окна, где оно ожидается.

Короче говоря, при участии нескольких одновременных запросов от одного и того же клиента, сообщения не гарантировано будут доставлены в то же окно, которое их создало, ни в некоторых случаях вообще. Обратите внимание, что это, как правило, не проблема в большинстве приложений и перестанет быть проблемой в HTML5, где каждое окно/вкладка будет иметь свой собственный контекст просмотра.

Настройки

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

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS

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

  • 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.1/ref/contrib/messages/

Spec-Zone.ru

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