Django使用message框架向模板中推送消息内容
Django模板中使用消息message框架
在web应用程序中,通常需要在处理表单或其他类型的用户输入之后向用户显示一次性通知消息(也称为“flash message”)。
为此,Django为匿名用户和经过身份验证的用户提供了对基于cookie和会话的消息传递的完全支持。messages框架允许您在一个请求中临时存储消息,并检索它们以在后续请求(通常是下一个请求)中显示。每条消息都有一个确定优先级的特定级别(例如,info、warning或error)。
启用消息
消息是通过中间件类和相应的上下文处理器实现的。
由django-admin startproject
创建的默认settings.py
已经包含了启用消息功能所需的所有设置:
-
django.contrib.messages
在INSTALLED_APPS
中。 - 中间件包含
django.contrib.sessions.middleware.SessionMiddleware
和django.contrib.messages.middleware.MessageMiddleware
,默认存储后端依赖于会话。这就是为什么必须启用SessionMiddleware,并且在中间件中的MessageMiddleware之前。 - 在模板设置中定义的DjangoTemplates的
context_processor
选项包含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
设置可用于更改最低记录级别(或可根据请求更改)。试图添加低于此级别的消息将被忽略。
消息标签
消息标签是消息级别的字符串表示形式,加上直接在视图中添加的任何额外标记(有关更多细节,请参阅下面添加额外消息标记)。标记存储在字符串中,并由空格分隔。通常,消息标记被用作CSS类,以根据消息类型定制消息样式。默认情况下,每个级别都有一个标签,它是自己常量的小写版本:
级别变量 | 标签 |
---|---|
DEBUG |
debug |
INFO |
info |
SUCCESS |
success |
WARNING |
warning |
ERROR |
error |
要更改消息级别的默认标记(内置或自定义),请将MESSAGE_TAGS
setting设置为包含希望更改的级别的字典。由于这扩展了默认标签,只需要为您希望覆盖的级别提供标记:
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.INFO: '',
50: 'critical',
}
在视图和模板中使用消息
add_message(request, level, message, extra_tags='', fail_silently=False)
添加消息
要添加消息,直接使用message的add_messages
方法
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呈现。否则,确保消息对模板上下文可用。
即使您知道只有一条消息,您仍然应该遍历消息序列,否则消息存储将不会为下一个请求清除。
上下文处理器还提供了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()
将返回配置的存储后端实例。
更多内容参看:https://docs.djangoproject.com/zh-hans/2.1/ref/contrib/messages/
消息类
class storage.base.Message
当您在模板中循环消息列表时,得到的是消息类的实例。这是一个非常简单的对象,只有几个属性:
-
消息
:消息的实际文本。 -
level
:描述消息类型的整数(参见上面的message levels部分)。 -
标记
:由空格分隔的所有消息标记(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)
有关最低记录级别函数的更多信息,请参见上面的消息级别。
添加额外的消息标签
为了对消息标记进行更直接的控制,您可以选择为任何add方法提供包含额外标记的字符串:
messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')
在该级别的默认标记之前添加额外的标记,并将它们分隔开来。
在禁用消息框架时静默失败
如果您正在编写一个可重用的应用程序(或其他代码片段),并且希望包含消息传递功能,但是如果用户不希望启用它,您可能会向add_message
方法家族传递一个额外的关键字参数fail_silent =True
。例如:
messages.add_message(
request, messages.SUCCESS, 'Profile details updated.',
fail_silently=True,
)
messages.info(request, 'Hello world.', fail_silently=True)
设置
fail_silent =True
只会隐藏当消息框架被禁用并试图使用add_message
方法家族之一时发生的MessageFailure。它不会隐藏由于其他原因可能发生的失败。
在基于类的视图中添加消息
class views.SuccessMessageMixin
success_message属性
向基于FormView
的类添加一个success
消息属性
get_success_message(cleaned_data)
:cleaned_data
是从用于字符串格式化的表单中清除的数据,例如
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)
的语法,可以使用从表单中清理出来的数据进行字符串插值。
get_success_message(self, cleaned_data)方法
对于ModelForms,如果需要从保存的对象访问字段,请覆盖get_success_message()
方法。例如:
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
使用实例
创建消息分类显示模板
当消息的类型不同时,显示不同的样式,创建message-alert-content.html文件
{% if messages %}
{% for message in messages %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.INFO %}
<div class="alert alert-info alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
【信息】:{{ message }}
</div>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %}
<div class="alert alert-success alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
【成功】:{{ message }}
</div>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.WARNING %}
<div class="alert alert-warning alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
【警告】:{{ message }}
</div>
{% endif %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}
<div class="alert alert-danger alert-dismissable">
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
【错误】:{{ message }}
</div>
{% endif %}
{% endfor %}
{% endif %}
UpdateView中使用message
form_valid定义消息添加
基于类的视图可以定义在验证表单的函数中
@method_decorator(login_required, name='dispatch')
class BlogNoticeUpdate(UpdateView):
model = BlogNotice
template_name = 'rearend/blog-notice-edit.html'
form_class = BlogNoticeForm
context_object_name = 'blog_notice'
# success_url = reverse_lazy('blog_admin:blog_notice') # 这儿不能使用reverse
def get_success_url(self): # 自定义跳转链接
return reverse_lazy('blog_admin:blog_notice', kwargs=self.kwargs)
def form_valid(self, form):
messages.success(self.request, '更新成功,该页面显示更新后的内容!')
return super(BlogNoticeUpdate, self).form_valid(form)
当然可以直接添加类方法,需要继承xxxMessageMixin父类
模板中包含消息模块
<div class="ibox-content">
<!--消息弹出-->
{% include 'rearend/includes/message-alert-content.html' %}
<form class="form-horizontal" method="post" action=".">
<div class="form-group">
<label for="id_blogger" class="col-sm-2 control-label">博主:</label>
<div class="col-sm-10">
<input type="text" name="blogger" value="{{ form.blogger.value }}" maxlength="10" required="" id="id_blogger" class="form-control">
</div>
</div>
<div class="form-group">
<label for="id_title" class="col-sm-2 control-label">公告标题:</label>
<div class="col-sm-10">
<input type="text" name="title" value="{{ form.title.value }}" maxlength="20" required="" id="id_title" class="form-control">
</div>
</div>
<div class="form-group">
<label for="id_content" class="col-sm-2 control-label">公告:</label>
<div class="col-sm-10">
<textarea name="content" cols="40" rows="10" id="id_content" class="form-control">{{ form.content.value }}</textarea>
</div>
</div>
{% csrf_token %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-primary" type="submit">保存内容</button>
</div>
</div>
</form>
</div>
image.png
函数中使用message
直接在相应的位置添加
messages.success(request, '删除专题成功!')
messages.error(request, 'xxx') # 使用消息框架