Django Signals

server/2024/9/24 8:54:46/

Django Signals

当某个事件发生的时候,signal(信号)允许senders(发送者)用来通知receivers(接收者),通知receivers干嘛?你想要recivers干嘛就可以干嘛。这在多处代码对同一个事件感兴趣的时候就有用武之地了。 比如:Django提供了一个built-in signal,叫django.core.signals.request_finished,这个signal会在一个HTTP请求完成后发送。下面就用一个简单的实例说明:在每个请求完成后打印"request finished"
####编写receiver
reciver是一个普通的callable对象,简单来说就是一个可被调用的函数,但是需要注意的是它需要接收一个参数sender和一个关键字参数**kwargs

def my_callback(sender, **kwargs):'''这是个receiver函数你可以在这里做爱做的的事情'''print senderprint kwargsprint("Request finished!")

这里我们先撇开sender和kwargs后面再分析,reciver函数写好之后,就需要把request_finished信号连接(注册)到my_callback

from django.core.signals import request_finished
request_finished.connect(my_callback)

现在请求一个URL路径/hello,后台打印的结果:

[31/Mar/2014 21:52:33] "GET /hello/ HTTP/1.1" 200 263
<class 'django.core.handlers.wsgi.WSGIHandler'>
{'signal': <django.dispatch.dispatcher.Signal object at 0x0262E510>}
Request finished!

以上就是一个signal的执行流程,那么django内部是怎么实现的呢?为什么调用了reciver.connect后,my_callback就能得到执行了呢?且看源代码分析:

request_finished定义在文件django.core.signals.py里面:

from django.dispatch import Signalrequest_started = Signal()
request_finished = Signal()
got_request_exception = Signal(providing_args=["request"])

request_finished就是Signal的实例。GET请求完成后会执行my_callback方法,为什么这么神奇,我们顺着request_finished的思路来猜想,既然是请求完成了,那么此时response对象也生成了,那么神奇的事情一定是在response里面发生的。去response.py文件里面看看:django.http.response.py

def close(self):for closable in self._closable_objects:try:closable.close()except Exception:passsignals.request_finished.send(sender=self._handler_class)

看到在response的close方法里面有send方法,而且这个sender就是我们在前面看到的django.core.handlers.wsgi.WSGIHandler',这个send方法会发送信号给所有的receivers。

#Signal.send方法的源代码:responses = []
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:return responsesfor receiver in self._live_receivers(sender):response = receiver(signal=self, sender=sender, **named)responses.append((receiver, response))
return responses

注意:你可以看到在for循环里面迭代的调用的receiver方法。以上就是django内部的执行原理。思考下send方式是signal的而不是sender的呢?从面向对象的角度来说,谁是对象的拥有者,谁就提供相应的方法。比如汽车的drive方法肯定是由汽车提供而不是由人。

####小结
我们需要做的只是编写receiver,然后调用signal.connect方法,相当于把receiver注册到signal上去。当事件触发时,相应的signal就会通知所有注册的receivers得到调用。尼玛,这是传说中的观察者模式。

连接receiver函数还有另外一个方法,用装饰器:

@receiver(request_finished):
def my_handler(sender, **kwages):'''

django还提供了很多内置的signals,比如:

  1. django.db.models.signals.pre_save & django.db.models.signals.post_save

    Sent before or after a model’s save() method is called.

  2. django.db.models.signals.pre_delete & django.db.models.signals.post_delete

    Sent before or after a model’s delete() method or queryset’s delete() method is called.

  3. django.db.models.signals.m2m_changed

    Sent when a ManyToManyField on a model is changed.

signal还可以指定具体的senders,比如pre_save这个signal是在Model对象保存在被发送,但是我希望只有某一类Model保存的时候才发送,你就可以指定:

@receiver(pre_save, MyModel):
def my_handle(sender, **kwargs):pass

这样每次只有保存MyModel实例后才会发送,其他的XXModel就会忽略掉。

完!


http://www.ppmy.cn/server/106240.html

相关文章

找在两个汉字中间的句号,如何写正则表达式?

要在两个汉字之间找到句号&#xff0c;可以使用以下正则表达式&#xff1a; (?<[\u4e00-\u9fff])。(?[\u4e00-\u9fff])解释&#xff1a; (?<[\u4e00-\u9fff]) 表示前面的字符是汉字。。 表示句号。(?[\u4e00-\u9fff]) 表示后面的字符是汉字。 这个正则表达式将匹配…

爆改YOLOv8 | 利用MB-TaylorFormer提高YOLOv8图像去雾检测

1&#xff0c;本文介绍 MB-TaylorFormer是一种新型多支路线性Transformer网络&#xff0c;用于图像去雾任务。它通过泰勒展开改进了softmax-attention&#xff0c;使用多支路和多尺度结构以获取多层次和多尺度的信息&#xff0c;且比传统方法在性能、计算量和网络重量上更优。…

Git的使用教程及常用语法02

四.将文件添加到仓库 创建仓库 git init查看仓库的状态 git status 添加到暂存区 git add提交 git commitgit status 可以查看当前仓库的状态信息&#xff0c;例如包含哪些分支&#xff0c;有哪些文件以及这些文件当前处在怎样的一个状态。 由于当前没有存储任何的东西&…

【Redis】

一.Widows下如何安装Redis? *(1) .下载地址: 点击跳转. 如下图: 在这里插入图片描述 *(2) .下载成功后将其移动到我们想要安装的目录下并且解压: 如下图: 在这里插入图片描述 *(3) .进入后有以下内容文件&#xff1a; *(4) .先点击redis-server.e…

SQLserver使用sql语句创建主键,外键,唯一约束,自增

在 SQL Server 中&#xff0c;可以通过 SQL 语句在创建表时或在现有表上添加约束&#xff0c;如主键&#xff08;PRIMARY KEY&#xff09;、外键&#xff08;FOREIGN KEY&#xff09;、唯一约束&#xff08;UNIQUE&#xff09;和自增&#xff08;IDENTITY&#xff09;。以下是如…

【蓝桥杯集训100题】scratch绘制扇子 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第28题

scratch绘制扇子 蓝桥杯集训100题第28题模拟练习解析 此题曾经作为第十届省赛的真题考过 一、题目要求 以坐标(0,0)点为中心绘制一把扇子;扇面和扇把都是三分之一圆,扇面的半径 为 100 左右,扇把的半径为 20 左右。 编程实现 每次点击绿旗后,舞台背景为白色,…

解锁 TypeScript Record 的奇妙用法:轻松搞定键值对!

在没有非常了解 Record 之前&#xff0c;定义对象的类型&#xff0c;一般使用 interface。它是 TS 中定义数据结构的一种方式&#xff0c;用来描述对象的形状、函数类型、类的结构等。 // 基本用法 interface User {name: string;age: number;isAdmin: boolean; }const user: …

如何使用ssm实现基于java的小型超市管理系统+vue

TOC ssm195基于java的小型超市管理系统vue 绪论 1.1 研究背景 现在大家正处于互联网加的时代&#xff0c;这个时代它就是一个信息内容无比丰富&#xff0c;信息处理与管理变得越加高效的网络化的时代&#xff0c;这个时代让大家的生活不仅变得更加地便利化&#xff0c;也让…