Django 信号详解

Django 信号详解

一、信号:

  • django自带一套信号机制来帮助我们在框架的不同位置之间传递信息。

    简单的说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(siganls)发送给一组接收者(receivers)

  • 信号系统包含的三要素:

    1.发送者:信号的发出放

    2.信号:信号本身

    3.接收者:信号的接收者

1.1内置信号:

  • Django提供一组内置的信号,让代码可以通过Django自己通知的操作,得到一些有用的通知:

    以下是model信号:from django.db.models.signals import xxxxxx

    model 信号简介
    pre_initmodel 执行其构造方法前,自动触发
    post_initmodel 执行其构造方法后,自动触发
    pre_savemodel 对象保存前,自动触发
    post_savemodel 对象保存后,自动触发
    pre_deletemodel 对象删除前,自动触发
    post_deletemodel 对象删除后,自动触发
    m2m_changed(m2m指的manytomany)m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared程序启动时,检测已注册的app中modal类,对于每一个类,自动触发

    以下是管理信号:from django.db.models.signals import pre_migrate, post_migrate

    管理信号简介
    pre_migrate执行migrate命令前,自动触发
    post_migrate执行migrate命令后,自动触发

    以下是请求返回信号:from django.core.signals import xxxxxx

    请求返回信号简介
    request_started请求到来前,自动触发
    request_finished请求结束后,自动触发
    got_request_exception请求异常后,自动触发

    以下是请求返回信号:from django.test.signals impor xxxxxx

    测试信号简介
    setting_changed使用test测试修改配置文件时,自动触发
    template_rendered使用test测试渲染模板时,自动触发

    以下是数据库信号:from django.db.backends.signals import xxxxxx

    数据库信号简介
    connection_created创建数据库连接时,自动触发

二、监听信号:

  • 要接收信号,使用Signal.connect()方法注册接收函数(接收器函数在信号发送时被调用)。

    Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)

    • 参数说明:
      • receiver – 将被连接到这个信号的回调函数。
      • sender – 指定一个特定的发送者接收信号。
      • weak – Django 默认将信号处理程序存储为弱引用。因此,如果您的接收器是本地函数,则可能会被回收。为了防止这种情况发生,当你调用信号的 connect() 方法时,传递 weak=False
      • dispatch_uid – 在可能发送重复信号的情况下,信号接收器的唯一标识符。

2.1:接收器函数:

  • 接收器可以是任何python函数或方法:

    def my_callback(sender, **kwargs):
        print("Request finished!")
    
    • 参数说明:

      • sender – 发送者(若是pre_save的话,就是model class)

      • **kwargs – 所有的信号都会发送关键字参数,并可能随时更改这些关键字参数。

        在request_finished的情况下,它被记录为不发送参数,就相当于:
        def my_callback(sender):
        	pass
        实际上这是错的,Django会抛出一个错误。
        这是因为在任何时候参数都可能被添加到信号中,并且接收器必须能够处理这些新的参数。
        

2.2:连接接收器函数:

两种方法可以将接收器连接到信号。

  • 手动连接路线:

    from django.core.signals import request_finished
    
    request_finished.connect(my_callback)
    
  • 使用装饰器receiver()

    from django.core.signals import request_finished
    from django.dispatch import receiver
    
    @receiver(request_finished)
    def my_callback(sender, **kwargs):
        print("Request finished!")
    

my_callback函数将在每次请求结束时被调用

2.3:连接到特定sender发送信号:

django.db.models.signals.pre_save 的情况下,sender 将是保存的模型类,因此您可以指示您只需要某个模型发送的信号:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel


@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

只有当 MyModel 的一个实例被保存时才会调用 my_handler 函数。

三、自定义和发送信号:

3.1:自定义信号:

import django.dispatch

mark_question_deleted = django.dispatch.Signal(providing_args=["user_id"])

声明一个mark_question)deleted信号,提供user_id参数接收器。

3.2:发送信号:

有种发送信号方式:

Signal.send(sender, **kwargs)

Signal.send_robust(sender, **kwargs)

要发送信号,请调用 Signal.send()(所有内置信号均使用此信号)或 Signal.send_robust()。你必须提供 sender 参数(这是大多数时候的类),并且可以提供尽可能多的其他关键字参数。

  • 举个栗子:使用mark_question_deleted信号:

    def send_reduce_user_attr_signals(report_type, body_obj):
        """减少用户发布/问题/回答/文章/评论的属性数量"""
            # 减少该用户的提问数
    	mark_question_deleted.send(sender=models.Question, user_id=body_obj.user_id)
    

    send()send_robust() 都返回一组元组对 [(receiver, response), ... ] 的列表,表示被调用的接收函数及其响应值的列表。

    send()send_robust() 的不同之处在于如何处理接收函数引发的异常。send() 不会捕获接收者引发的任何异常;它只是允许错误传播。因此,在出现错误时,并非所有接收机都可能被通知信号。

    send_robust() 捕获从 Python 的 Exception 类派生的所有错误,并确保所有接收器都被通知信号。如果发生错误,则错误实例会返回到引发错误的接收方的元组对中。

3.3:断开信号:

Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)

要从信号中断开接收器,请调用 Signal.disconnect()。参数如 Signal.connect() 中所述。如果接收器断开,该方法返回 True,否则返回 False

receiver 参数指示注册的接收者断开连接。如果使用 dispatch_uid 来标识接收者,它可能是 None

四、自定义信号使用实例:

  • 如果上述代码不太好理解,下面简单举个栗子:

    1.首先在 url.py 创建要访问的url

    from django.conf.urls import url, include
    from . import views, signals
    urlpatterns = [
        url(r'^signal/test/$', views.create_signal) 
    ]
    

    2.在它的views.py中创建了一个create_signal视图,通过/signal/可以访问这个视图

    from django.shortcuts import HttpResponse
    import time
    import django.dispatch
    from django.dispatch import receiver
    
    # 创建一个自定义信号(信号本身)
    # 自定义信号名就是work_done,接收请求的path、time 是两个参数
    work_done = django.dispatch.Signal(providing_args=['path', 'time'])
    
    # 请求url地址,将访问这个FBV视图
    def create_signal(request):
    	# 获取请求的url
        url_path = request.path
        print('准备发送一个信号出去哦')
    	# 发送者:信号的发出放
        work_done.send(create_signal, path=url_path, time=time.strftime("%Y-%m-%d %H:%M:%S"))
        return HttpResponse('OK')
    
    # 接收者:信号的接收者(接收自定义信号名)
    @receiver(work_done, sender=create_signal)
    def my_callback(sender, **kwargs):
        print("我在%s时间收到来自%s的信号,请求url为%s" % (kwargs['time'], sender, kwargs["path"]))
    

    3.启动Django服务器,访问:http://127.0.0.1:8000/signal/ ,输出内容:

    准备发送一个信号出去哦
    我在2019-06-06 16:23:09时间收到来自<function create_signal at 0x0000000005269048>的信号,请求url为/order/
    
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值