消息框架¶
在 Web 应用程序中,您经常需要在处理表单或其他类型的用户输入后向用户显示一次性通知消息(也称为“闪现消息”)。
为此,Django 为匿名用户和已认证用户提供了基于 Cookie 和会话的消息传递的全面支持。消息框架允许您在一个请求中临时存储消息,并在后续请求(通常是下一个请求)中检索这些消息以进行显示。每条消息都用一个特定的level
标记,该标记决定其优先级(例如,info
、warning
或error
)。
启用消息¶
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
,如果消息无法容纳在一个 Cookie 中,则回退到使用SessionStorage
。它还需要 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 logging 模块的可配置级别架构。消息级别允许您按类型对消息进行分组,以便可以在视图和模板中对它们进行过滤或以不同的方式显示。
可以直接从django.contrib.messages
导入的内置级别是
常量 |
用途 |
---|---|
|
与开发相关的消息,这些消息将在生产部署中被忽略(或删除) |
|
面向用户的提示性消息 |
|
操作成功,例如“您的个人资料已成功更新” |
|
未发生故障,但可能即将发生 |
|
操作未成功或发生其他故障 |
MESSAGE_LEVEL
设置可用于更改最低记录级别(也可以按请求更改)。尝试添加低于此级别的消息将被忽略。
在视图和模板中使用消息¶
添加消息¶
要添加消息,请调用
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.")
显示消息¶
在您的模板中,使用类似以下内容
{% 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.")
创建自定义消息级别时,应注意避免重载现有级别。内置级别的值是:
级别常量 |
值 |
---|---|
|
10 |
|
20 |
|
25 |
|
30 |
|
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)
有关最小记录级别功能的更多信息,请参见上面的 消息级别。
禁用消息框架时静默失败¶
如果您正在编写可重用的应用程序(或其他代码),并且想要包含消息功能,但不希望在用户不需要时强制他们启用它,您可以向任何 add_message
系列方法传递一个额外的关键字参数 fail_silently=True
。例如:
messages.add_message(
request,
messages.SUCCESS,
"Profile details updated.",
fail_silently=True,
)
messages.info(request, "Hello world.", fail_silently=True)
注意
设置 fail_silently=True
只会隐藏在消息框架被禁用并且尝试使用 add_message
系列方法之一时会发生的 MessageFailure
。它不会隐藏可能由于其他原因发生的故障。
在基于类的视图中添加消息¶
- 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()
方法。
ModelForms 的示例 views.py:
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 设置。
测试¶
此模块提供了一种定制的测试断言方法,用于测试附加到 HttpResponse
的消息。
要利用此断言,请将 MessagesTestMixin
添加到类层次结构中。
from django.contrib.messages.test import MessagesTestMixin
from django.test import TestCase
class MsgTestCase(MessagesTestMixin, TestCase):
pass
然后,在您的测试中继承自 MsgTestCase
。