Skip to main content

消息框架

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

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

启用邮件

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

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

  • 'django.contrib.messages'INSTALLED_APPS 中。

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

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

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

如果不想使用消息,可以从 INSTALLED_APPS 中删除 'django.contrib.messages',从 MIDDLEWARE 中删除 MessageMiddleware 行,从 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 是默认存储类。如果不适合您的需要,可以通过将 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

操作是 成功或发生其他故障

MESSAGE_LEVEL 设置可用于更改最小记录级别(或可以是 changed per request)。尝试添加级别小于此级别的邮件将被忽略。

消息标签

消息标记是消息级别的字符串表示,加上直接添加到视图中的任何额外标记(有关详细信息,请参阅下面的 Adding extra message tags)。标签存储在字符串中,并由空格分隔。通常,消息标签用作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)[源代码]

添加消息

要添加消息,请调用:

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:描述消息类型的整数(参见上面的 message levels 部分)。

  • tags:组合所有消息的标签(extra_tagslevel_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 设置提供映射。

注解

如果要创建可重用的应用程序,建议仅使用内置的 message levels,而不依赖于任何自定义级别。

根据请求更改最小记录级别

可以通过 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)

有关最小记录级功能的详细信息,请参阅上面的 Message levels

添加额外的消息标签

要更直接地控制消息标记,您可以选择向任何添加方法提供包含额外标记的字符串:

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() 方法。

ModelForms的examples.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或会话的后端的行为都是未定义的。例如,如果客户端在第一窗口重定向之前发起在一个窗口(或tab)中创建消息并且然后在另一个窗口中获取任何单元化消息的请求,则该消息可以出现在第二窗口中而不是第一窗口中窗口,它可能是预期的。

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

设置

一些 settings 让你控制消息行为:

对于使用Cookie的后端,Cookie的设置取自会话Cookie设置: