消息框架

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

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

启用消息

消息通过middleware类和相应的context processor实现。

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

  • 'django.contrib.messages'位于INSTALLED_APPS中。

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

    默认的storage backend依赖sessions 这就是为什么SessionMiddleware必须启用并出现在MIDDLEWAREMessageMiddleware之前的原因。

  • The 'context_processors' option of the DjangoTemplates backend defined in your TEMPLATES setting contains 'django.contrib.messages.context_processors.messages'.

If you don’t want to use messages, you can remove 'django.contrib.messages' from your INSTALLED_APPS, the MessageMiddleware line from MIDDLEWARE, and the messages context processor from TEMPLATES.

配置消息引擎

存储后端

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

Django在django.contrib.messages中提供了三个内置的存储类:

storage.session。的sessionStorage T0> ¶ T1>

这个类存储请求会话中的所有消息。 因此它需要Django的contrib.sessions应用程序。

storage.cookie。 CookieStorage T0> ¶ T1>

该类将消息数据存储在cookie中(使用秘密散列进行签名以防止操作),以便跨请求保留通知。 如果cookie数据大小超过2048字节,则会丢弃旧邮件。

storage.fallback。 FallbackStorage T0> ¶ T1>

这个类首先使用CookieStorage,并回退到使用SessionStorage来处理无法放入单个cookie的消息。 它也需要Django的contrib.sessions应用程序。

这种行为可以避免在可能的情况下写入会话。 它应该提供一般情况下的最佳性能。

FallbackStorage is the default storage class. 如果它不适合您的需要,可以通过将MESSAGE_STORAGE设置为完整的导入路径来选择另一个存储类别,例如:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
storage.base。 BaseStorage T0> ¶ T1>

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

消息级别

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

可以直接从django.contrib.messages导入的内置级别是:

不变 目的
DEBUG 开发相关的消息将在生产部署中被忽略(或删除)
信息 用户的信息性消息
成功 一个行动是成功的,例如“您的个人资料已成功更新”
警告 失败没有发生,但可能迫在眉睫
错误 一个行动没有成功或发生了一些其他故障

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

消息标签

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

级别常量 标签
DEBUG 调试
信息 信息
成功 成功
警告 警告
错误 错误

要更改消息级别(内置或自定义)的默认标记,请将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)[source]

添加一条消息

要添加消息,请致电:

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)[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() will return an instance of the configured storage backend.

Message

storage.base。消息 T0> ¶ T1>

当你遍历模板中的消息列表时,你会得到Message类的实例。 这是一个相当简单的对象,只有几个属性:

  • message: The actual text of the message.
  • level:描述消息类型的整数(参见上面的消息级别部分)。
  • 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
信息 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方法:

messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')

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

当消息框架被禁用时,默默地失败

If you’re writing a reusable app (or other piece of code) and want to include messaging functionality, but don’t want to require your users to enable it if they don’t want to, you may pass an additional keyword argument fail_silently=True to any of the add_message family of methods. 例如:

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系列方法。 它不会隐藏可能由于其他原因而发生的故障。

在基于类的视图中添加消息

观点。 SuccessMessageMixin T0> ¶ T1>

将成功消息属性添加到FormView基类

get_success_message T0>( cleaned_data T1>)¶ T2>

cleaned_data is the cleaned data from the form which is used for string formatting

示例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"

使用%(field_name)s语法从form中清除的数据可用于字符串插值。 对于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

并行请求的行为

Due to the way cookies (and hence sessions) work, the behavior of any backends that make use of cookies or sessions is undefined when the same client makes multiple requests that set or get messages in parallel. 例如,如果客户端启动在一个窗口(或选项卡)中创建消息的请求,然后另一个客户端在另一个窗口中提取任何未合并的消息,则在第一个窗口重定向之前,消息可能会显示在第二个窗口中,而不是第一个窗口中窗口在哪里可能是预期的。

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

设置¶ T0>

几个settings可以控制消息行为:

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