Spec-Zone.ru › Django 5.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 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
END_OF_DOCUMENT_MARKER

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

Этот модуль предлагает специализированный метод проверки утверждений для тестирования сообщений, прикрепленных к 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.2/ref/contrib/messages/

Spec-Zone.ru

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