Spec-Zone.ru › Django 1.9

The messages framework

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

Для этого Django предоставляет полную поддержку хранения сообщений на основе файлов cookie и сессии, как для анонимных, так и для авторизованных пользователей. Модуль сообщений позволяет временно хранить сообщения в одном запросе и извлекать их для отображения в последующем запросе (обычно в следующем). Каждое сообщение помечено определенным level, который определяет его приоритет (например, info, warning, или error).

Enabling messages

Сообщения реализованы с помощью класса средства промежуточного ПО и соответствующего обработчика контекста.

По умолчанию settings.py созданный django-admin startproject уже содержит все настройки, необходимые для активации функциональности сообщений:

  • 'django.contrib.messages' находится в INSTALLED_APPS.
  • MIDDLEWARE_CLASSES содержит 'django.contrib.sessions.middleware.SessionMiddleware' и 'django.contrib.messages.middleware.MessageMiddleware'.

    По умолчанию хранилище сообщений использует сессии. Поэтому SessionMiddleware должен быть включен и должен предшествовать MessageMiddleware в MIDDLEWARE_CLASSES.

  • Опция 'context_processors' бэкенда DjangoTemplates, определенного в вашем параметре TEMPLATES, содержит 'django.contrib.messages.context_processors.messages'.

Если вы не хотите использовать сообщения, вы можете удалить 'django.contrib.messages' из вашего INSTALLED_APPS, строку MessageMiddleware из MIDDLEWARE_CLASSES и обработчик контекста messages из TEMPLATES.

Configuring the message engine

Storage backends

Модуль сообщений может использовать различные бэкенды для хранения временных сообщений.

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.

Message levels

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

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

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

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

Message tags

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

Level Constant Tag
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',
}

Using messages in views and templates

add_message(request, level, message, extra_tags='', fail_silently=False) [source]

Adding a message

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

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.')

Displaying messages

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() вернёт экземпляр конфигурированного бэкенда хранилища.

The Message class

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/1.9/ref/contrib/messages/

Spec-Zone.ru

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