django 信号(signal)的问题

依旧是做django1.6 python2.7 升级到 django3.2 python3.8的任务。刚好本次任务涉及几个骚情的东西,这里总结一下,一个是 信号,一个是 django自带的api(本篇不介绍,会在下一篇介绍)

首先,先讲讲对信号这个东西的整体理解:

这东西给我的感觉就像是这样的:

本来代码应该是按照顺序执行,从 节点1 直接运行至 节点4 ,但是使用信号这个东西以后,就成了上面的样子,在节点1处,发信号,然后立刻就会被节点2处监测并收到信号,于是执行收到信号后应该干的事,完事后就进入到了节点3处,也是就是说,节点2到节点3就是收到信号后,做事情的过程,这个过程是独立的,是一个新的线程去做的,完全不影响当下代码的执行。

这就是一个信号整体执行的过程。

接下来看看信号这个东西怎么用。

这东西从执行的过程中,不难发现,首先,得有个信号,然后这个信号得绑定一个要做的事情(python中,不就是函数么),最后,就是得有个地方去发信号。于是过程就成了这个样子,在节点1处,发送信号,节点2,3,做与信号绑定的事情。

同样,具体的实现,也差不多是这个步骤:(django本身有自带的信号,这里先讲自定义信号)

# 先自定义一个信号,这里注意,所有的自定义信号都必须是来自于django的Signal模块,就是说,我们所有的自定义信号都是基于django自带的Signal模块来搞的。然后就是给我们的信号起名字,下面示例中起名位 pizza_done,这里其实说到底,Signal是一个类对象,我们给自定义信号起名字的过程就是创建实例对象的过程

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings""size"])

顺便看下Signal的参数: 

一般情况,我们都是只用第一个参数,第二个参数都是走默认。

这里注意:第一个参数是指我们给这个信号绑定具体事件(函数)时,这个函数所需要的参数。

# 接下来就是制定事件,并且将事件与信号绑定

def do_somethings(sender, **kwargs):

    print("do_somethings")

    print(sender,kwargs)

  

pizza_done.connect(do_somethings)

# 最后,就是触发信号

from   xxx.xxx.xxx import pizza_done

  

pizza_done.send(sender='seven',toppings=123, size=456)

这里注意,一般情况,都会带,sender 这个参数,因为我们需要知道是谁触发的信号,而且实际应用中,这个sender往往会使个类对象的实例对象。

看一个实际的应用:

 这样以来,当服务启动时,在文件加载的时候,就一次性完成了,三个信号对象与相应事件的绑定动作。

 这里就是触发发送的动作的地方,这里是django modle模型,重写了save方法,也就是说,在保存一条模型数据的时候,就会触发发送信号的动作,然后,相应的信号就会去做约定好的事情。

这里注意,发送时,使用了 send_robust 方法,这个方法和send大致一样,但是会比send方法更加友好,因为使用send方法,一旦出错,完全是没有相关提示的,而 send_robust 方法,会将相关错误,比较清晰明确的打印到控制台。

上述为自定义信号创建的一种方法,还有一种方法,是采用装饰器直接完成事件的创建和与信号对象的绑定动作。

这种类型,依旧属于自定义信号,使用装饰器 @receiver 直接可以将信号对象,和要做的事件绑定。一旦有地方发送信号,这里就会立刻执行下面的函数。

ok,这就是自定义信号的创建过程。

 然后,django本身也有许多内建的信号,比如:

Model signals
    pre_init                    # model初始化前触发,自动触发
    post_init                   # model初始化后触发,自动触发
    pre_save                    # save()方法前触发,自动触发
    post_save                   # save()方法后触发,自动触发
    pre_delete                  # delete()方法前触发,自动触发
    post_delete                 # delete()方法后触发,自动触发
    m2m_changed                 # ManyToManyField字段改变时触发,django的model中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中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          # 创建数据库连接时,自动触发
Django 提供了一系列的内建信号,允许用户的代码获得DJango的特定操作的通知。这包含一些有用的通知:
django.db.models.signals.pre_save & django.db.models.signals.post_save
 
在模型 save()方法调用之前或之后发送。
django.db.models.signals.pre_delete & django.db.models.signals.post_delete
 
在模型delete()方法或查询集的delete() 方法调用之前或之后发送。
django.db.models.signals.m2m_changed
 
模型上的 ManyToManyField 修改时发送。
django.core.signals.request_started & django.core.signals.request_finished
 
Django建立或关闭HTTP 请求时发送。
from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created
 
def callback(sender, **kwargs):
        print("pre_save_callback")
        print(sender,kwargs)
 
pre_save.connect(callback)      # 该脚本代码需要写到app或者项目的初始化文件中,当项目启动时执行注册代码


# 或者这样

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

接下来看个实例:

 我重点解释下,这段代码。这里首先用的是django的内建信号,那么问题来了,内建信号是固定的,唯一的,没法搞什么实例对象,那么如果有多个对象,都触发了内建信号,这咋整,ok,如果这里跟信号绑定的是一个公共操作,大家伙都要执行,那么没问题,都触发信号了,那就都执行相关的具体事件就可以了,但是如果是a对象触发了信号,但是想干这件事,b对象也触发了信号,但是想干另一件事,咋弄,所以新的使用方式就出现了,就是上面的方式。@receiver 里面,第一个参数,就是信号对象本身,第二个参数,sender 就是用来绑定触发事件的对象,比如是a触发的,还是b触发的,那么上述代码的整体意思就变成了,当sender为 User对象的时候,当User对象触发信号对象 builtin_signals.post_save 的时候,执行函数 create_settings。如果是 aaa 也触发了builtin_signals.post_save信号的时候,是不会执行函数 create_settings的。这就实现了,具体事件,具体对待的处理问题的方式。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值