Фреймворк сообщений

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

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

класс storage.session.SessionStorage

Этот класс хранит все сообщения внутри сеанса запроса. Поэтому для этого требуется contrib.sessionsприложение Django .

класс storage.cookie.CookieStorage

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

Изменено в Django 3.2:

Формат сообщений изменен на Формат, соответствующий RFC 6265 .

класс storage.fallback.FallbackStorage

Этот класс сначала использует CookieStorage, а затем возвращается к использованию SessionStorageдля сообщений, которые не могут поместиться в один файл cookie. Также требуется contrib.sessionsприложение Django .

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

FallbackStorage- класс хранения по умолчанию. Если он вам не подходит, вы можете выбрать другой класс хранилища, установив MESSAGE_STORAGEего полный путь импорта, например:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
класс storage.base.BaseStorage

Для того, чтобы написать свой собственный класс хранения, подкласс BaseStorageкласса в django.contrib.messages.storage.baseи реализовать _getи _storeметоды.

Уровни сообщений

Инфраструктура сообщений основана на конфигурируемой архитектуре уровня, аналогичной архитектуре модуля ведения журнала Python. Уровни сообщений позволяют группировать сообщения по типу, чтобы их можно было фильтровать или по-разному отображать в представлениях и шаблонах.

Встроенные уровни, которые можно импортировать 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( запрос , уровень , сообщение , extra_tags = '' , fail_silently = False )

Добавление сообщения

Чтобы добавить сообщение, позвоните:

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( запрос )

В вашем шаблоне используйте что-то вроде:

{% 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Класс

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

Добавление сообщений в представления на основе классов

класс 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

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

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

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

Настройки

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

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

Copyright ©2021 All rights reserved