" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper博主等级

千里之行,始于足下

  • 累计撰写 203 篇文章
  • 累计创建 14 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
Web

Django 信号机制、消息框架

PySuper
2021-04-26 / 0 评论 / 0 点赞 / 12 阅读 / 13007 字
温馨提示:
所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

信号机制

https://docs.djangoproject.com/zh-hans/2.1/ref/signals/

内置信号参数

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
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区