信号机制
内置信号参数
Model signals
pre_init # model执行构造方法前,触发
post_init # model执行构造方法后,触发
pre_save # model执行save对象保存前,触发
post_save # model执行save对象保存前,触发
pre_delete # model执行delete对象删除前,触发
post_delete # model执行delete对象删除前,触发
m2m_changed # model使用多对多字段操作第三张表前后,触发
class_prepared # 程序启动时,检测已注册的model类,对每个类,触发
Management signals
pre_migrate # 执行migrate前,触发
post_migrate # 执行migrate后,触发
Request/response signals
request_started # 请求到来前,触发
request_finished # 请求结束后,触发
got_request_exception # 请求异常后,触发
Test signals
setting_changed # 使用test测试修改配置文件,触发
template_rendered # 使用test测试渲染模板时,触发
Database Wrappers
connection_created # 创建数据库连接时,触发
pre_save
sender
: 模型类instance
: 保存的实际实例(保存后的model数据对象)using
: 正在使用的数据库别名update_fields
: 要传递给更新的字段集model.save(),或者None 如果update_fields未传递给它save()raw
:- 布尔值,True如果模型完全按照提供的方式保存。
- 不应该查询/修改数据库中的其他记录,因为数据库可能尚未处于一致状态
post_save
sender
:模型类instance
:保存的实际实例created
:布尔值; True如果创建了新记录(True表示数据创建)using
:正在使用的数据库别名update_fields
:要传递给更新的字段集model.save(),或者None 如果update_fields未传递给它save()raw
:- 布尔值,True如果模型完全按照提供的方式保存。
- 不应该查询/修改数据库中的其他记录,因为数据库可能尚未处于一致状态
pre_delete
- sender:模型类
- instance:删除的实际实例
- using:使用的数据库别名
post_delete
- sender:类
- instance:删除的实际实例(该对象将不再存在于数据库中,因此请谨慎对待此实例)
- using:使用的数据库别名
内置信号监听
手动连接
from django.db.models.signals import post_delete
def my_callback(sender, **kwargs):
print(sender)
print("信号已接收")
post_delete.connect(my_callback) # 信号连接接收器,用于收到信号的回调,如果想要指定某个表对象,直接指定sender
# connect参数接收
"""
receiver - 将连接到此信号的回调函数。回调函数名,不带括号
sender - 指定从中接收信号的特定发送方。
weak - Django默认将信号处理程序存储为弱引用。因此,如果您的接收器是本地功能,它可能被垃圾收集。为了防止这种情况,请weak=False在调用信号connect()方法时通过。
dispatch_uid - 在可能发送重复信号的情况下信号接收器的唯一标识符。
"""
receiver 装饰器
from django.dispatch import receiver
from django.db.models.signals import post_delete
from app.models import UCenter
@receiver(post_delete, sender=UCenter) # post_delete指定信号触发类型,sender指定到具体对象
def delete_u2user(sender, instance, **kwargs): # instance表示被删除的对象
print(sender, instance)
自定义信号
定义信号
from django.dispatch import Signal
# 声明一个test_signal的信号,提供给接收器name跟age两个参数(可自定义参数)
test_signal = Signal(providing_args=["name", "age"])
注册信号
def my_callback(sender, **kwargs):
print(sender)
print("信号已接收")
test_signal.connect(my_callback) # 注册信号,指定接收器为my_callback
触发信号
from xxx import test_signal
test_signal.send(sender='test', name='zzq', age='18') # 触发信号,发送name,age参数信息
当然这样在选择发送信号的方式有两种一种使用Signal.send,还有一种是Signal.send_robut。
send () 与 send_robust () 处理接收器功能引起的异常的方式不同。
send () 并不能捕获由接收器提出的任何异常; 它只是允许错误传播。
因此,在面对错误时,不是所有接收器都可以被通知信号。
send_robust () 捕获从 Python Exception 类派生的所有错误,并确保所有接收器都收到信号通知。
如果发生错误,则会在引发错误的接收器的元组对中返回错误实例。
django auth 信号
user_logged_in = Signal(providing_args=['request', 'user'])
user_login_failed = Signal(providing_args=['credentials', 'request'])
user_logged_out = Signal(providing_args=['request', 'user'])
消息框架
启用消息框架
- INSTALLED_APPS 中注册
django.contrib.messages
- MIDDLEWARE 中添加
django.contrib.sessions.middleware.SessionMiddleware
django.contrib.messages.middleware.MessageMiddleware
- messages 框架默认使用的存储后端为 sessions
- 所以 Session 中间件必须被启用,并出现在 Message 中间件之前
- TEMPLATES 设置中DjangoTemplates 选项包含的 ‘context_processors’ 配置项要包含
django.contrib.messages.context_processors.messages
消息引擎
存储后端
-
class storage.session.SessionStorage
-
class storage.cookie.CookieStorage
-
class storage.fallback.FallbackStorage
-
FallbackStorage 是默认的存储后端。
如果它不适合你的,你可以通过设置 MESSAGE_STORAGE 选择另外一个存储后端,例如:
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
消息级别
消息框架的级别是可配置的,与 Python 的 logging 模块类似
MESSAGE_LEVEL
设置可以用来改变记录的最小级别(参考前面的 Django 设置章节),小于这个级别的消息将被忽略。
级别 | 说明 |
---|---|
DEBUG | 将在生产部署中忽略(或删除)的与开发相关的消息 |
INFO | 普通提示信息 |
SUCCESS | 成功信息 |
WARNING | 警告信息 |
ERROR | 已经发生的错误信息 |
消息样式
若要修改消息级别的默认样式,设置 MESSAGE_TAGS
,按如下例子所示:
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.INFO: '',
50: 'critical',
}
级别 | 样式 |
---|---|
DEBUG | debug |
INFO | info |
SUCCESS | success |
WARNING | warning |
ERROR | error |
使用消息框架
添加消息
方法原型:add_message (request, level, message, extra_tags=’’, fail_silently=False)[source]
新增一条消息:
from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')
提供请求对象 request(直接用就行),消息级别、消息内容字符串三个参数即可。
或者使用下面的快捷方式
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 %}
相关说明:
- 通过 if 判断是否有消息;
- messages 是一个列表,必须用 for 标签循环它;
- 即使你知道只有一条消息,也要迭代 messages 列表,否则下个请求中,上个请求的消息不会被清除。
- 可以通过 message.tags 拿到每个消息的 CSS 样式
有一个 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 %}
说明:
- 可以通过 message.level 拿到当前消息的级别数值;
- 将它与 DEFAULT_MESSAGE_LEVELS.ERROR 进行对比;
- 如果一样,就说明当前消息级别为 ERROR,需要显示到页面上。
在模板的外面,比如视图中,可以使用 get_messages()
方法获取消息:
from django.contrib.messages import get_messages
storage = get_messages(request)
for message in storage:
do_something_with_the_message(message)
说明:
- get_messages () 返回的是存储后端的一个实例。
- 循环这个实例,可以获得每条消息
对于每一个消息实例,都包含下面的属性,可以在模版或视图中调用:
- message: 消息的实际内容文本。不要使用 message.message,直接 message。
- level: 消息级别,一个整数。
- tags: 一个字符串,由该消息的所有标签 (extra_tags 和 tags) 组合而成,组合时用空格分割开这些标签。
extra_tags
: 一个字符串,由该消息的定制标签组合而成,并用空格分割。默认为空。level_tag
: 当前消息级别对应的 CSS 字符串,前面介绍过。
自定义消息级别
消息级别只是一个整数常量,所以,可以定义自己的级别常量,例如:
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
# 修改最小级别为DEBUG
messages.set_level(request, messages.DEBUG)
messages.debug(request, 'Test message...')
# 在另外一个视图中修改最小级别为WARNING
messages.set_level(request, messages.WARNING)
messages.success(request, 'Your profile was updated.') # 被忽略,不记录
messages.warning(request, 'Your account is about to expire.') # 记录
# 将最小级别恢复到默认值
messages.set_level(request, None)
set_level()
方法接收 request 为第一参数,消息级别为第二参数。
类似的,当前有效的记录级别可以用 get_level()
方法获取:
from django.contrib import messages
current_level = messages.get_level(request)
添加额外的消息 CSS 样式
要添加自定义的消息 CSS 样式,可以通过 extra_tags 参数:
messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')
消息过期机制
默认情况下,如果包含消息的迭代器完成迭代后,当前请求中的消息都将被删除。
如果你不想这么做,想保留这些消息,那么需要显式的指定 used 参数为 False,如下所示:
storage = messages.get_messages(request)
for message in storage:
do_something_with(message)
storage.used = False
评论区