消息框架 — Django 文档

来自菜鸟教程
Django/docs/2.2.x/ref/contrib/messages
跳转至:导航、​搜索

消息框架

在 Web 应用程序中,在处理表单或某些其他类型的用户输入后,您需要向用户显示一次性通知消息(也称为“闪现消息”),这很常见。

为此,Django 为匿名和经过身份验证的用户提供对基于 cookie 和会话的消息传递的全面支持。 消息框架允许您在一个请求中临时存储消息并检索它们以在后续请求(通常是下一个请求)中显示。 每条消息都标有确定其优先级的特定 level(例如,infowarningerror)。

启用消息

消息通过 中间件 类和相应的 上下文处理器 实现。

django-admin startproject 创建的默认 settings.py 已经包含启用消息功能所需的所有设置:

  • 'django.contrib.messages':setting:`INSTALLED_APPS` 中。

  • :setting:`MIDDLEWARE` 包含 'django.contrib.sessions.middleware.SessionMiddleware''django.contrib.messages.middleware.MessageMiddleware'

    默认的 存储后端 依赖于 会话 。 这就是为什么 SessionMiddleware 必须启用并出现在 :setting:`MIDDLEWARE` 中的 MessageMiddleware 之前。

  • :setting:`TEMPLATES` 设置中定义的 DjangoTemplates 后端的 'context_processors' 选项包含 'django.contrib.messages.context_processors.messages'

如果您不想使用消息,可以从 :setting:`INSTALLED_APPS`:setting:` 中的 MessageMiddleware 行中删除 'django.contrib.messages' MIDDLEWARE`,以及来自 :setting:`TEMPLATES`messages 上下文处理器。


设置消息引擎

存储后端

消息框架可以使用不同的后端来存储临时消息。

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 是默认的存储类。 如果它不适合您的需求,您可以通过将 :setting:`MESSAGE_STORAGE` 设置为其完整导入路径来选择其他存储类,例如:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
class storage.base.BaseStorage

要编写自己的存储类,请在 django.contrib.messages.storage.base 中继承 BaseStorage 类并实现 _get_store 方法。


消息级别

消息框架基于类似于 Python 日志记录模块的可配置级别架构。 消息级别允许您按类型对消息进行分组,以便它们可以在视图和模板中进行过滤或以不同方式显示。

可以直接从django.contrib.messages中导入的内置关卡有:

常量 目的
DEBUG 与开发相关的消息,在生产部署中将被忽略(或删除)
INFO 给用户的参考消息
SUCCESS 一个动作成功,例如 “您的个人资料已成功更新”
WARNING 未发生的故障,但可能即将发生
ERROR 操作 成功或发生其他一些失败

:setting:`MESSAGE_LEVEL` 设置可用于更改最小记录级别(或者可以根据请求 更改 )。 尝试添加低于此级别的消息将被忽略。


消息标签

消息标签是消息级别的字符串表示以及直接添加到视图中的任何额外标签(有关更多详细信息,请参阅下面的 添加额外的消息标签 )。 标签存储在一个字符串中,并用空格分隔。 通常,消息标签用作 CSS 类来根据消息类型自定义消息样式。 默认情况下,每个级别都有一个标记,它是其自身常量的小写版本:

消息常量 标签
DEBUG debug
INFO info
SUCCESS success
WARNING warning
ERROR error

要更改消息级别的默认标签(内置或自定义),请将 :setting:`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)

添加一个消息

要添加消息,请致电:

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)

在你的模板中,使用类似的东西:

{% 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_tagslevel_tag)组合而成的字符串。
  • extra_tags:包含此消息的自定义标签的字符串,以空格分隔。 默认为空。
  • level_tag:级别的字符串表示。 默认情况下,它是关联常量名称的小写版本,但如果需要,可以使用 :setting:`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 中识别自定义级别,则需要通过 :setting:`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')

额外的标签添加在该级别的默认标签之前,并以空格分隔。


当消息框架被禁用时静默的失败了

如果您正在编写一个可重用的应用程序(或其他代码段)并希望包含消息传递功能,但又不想要求您的用户启用它(如果他们不想启用它),您可以传递一个额外的关键字参数 [ X220X] 到 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() 方法。

ModelForms的示例views.py:

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

并行请求的行为

由于 cookie(以及会话)的工作方式,当同一个客户端发出多个并行设置或获取消息的请求时,任何使用 cookie 或会话的后端的行为都是未定义的。 例如,如果客户端发起一个请求,在一个窗口(或选项卡)中创建一条消息,然后另一个在另一个窗口中获取任何统一消息,则在第一个窗口重定向之前,该消息可能会出现在第二个窗口而不是第一个窗口中可能会出现的窗口。

简而言之,当涉及来自同一个客户端的多个同时请求时,不能保证消息被传送到创建它们的同一个窗口,在某些情况下,甚至根本不能保证。 请注意,这在大多数应用程序中通常不是问题,并且在 HTML5 中将成为非问题,其中每个窗口/选项卡都有自己的浏览上下文。


配置

一些 设置 可让您控制消息行为:

对于使用 cookie 的后端,cookie 的配置来自会话 cookie 配置: