Spec-Zone.ru › Django 5.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 Message [source]

Когда вы перебираете список сообщений в шаблоне, вы получаете экземпляры класса 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 AuthorCreateView(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 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

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

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

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

Настройки

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

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS

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

  • SESSION_COOKIE_DOMAIN
  • SESSION_COOKIE_SECURE
  • SESSION_COOKIE_HTTPONLY

Тестирование

Новое в Django 5.0.

Этот модуль предлагает специализированный метод проверки утверждений для проверки сообщений, прикреплённых к HttpResponse.

Чтобы воспользоваться этим утверждением, добавьте MessagesTestMixin в иерархию классов:

from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase


class MsgTestCase(MessagesTestMixin, TestCase):
    pass

Затем, унаследуйте от MsgTestCase в своих тестах.

MessagesTestMixin.assertMessages(response, expected_messages, ordered=True) [source]

Утверждает, что messages, добавленные к response, соответствуют expected_messages.

expected_messages — это список объектов Message.

По умолчанию сравнение зависит от порядка. Вы можете отключить это, установив аргумент ordered в False.

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

Spec-Zone.ru

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