当前位置: 首页 > news >正文

Django Signals

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就会忽略掉。

完!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【html+css 绚丽Loading】 - 000003 乾坤阴阳轮
  • 【算法/学习】双指针
  • 25考研计算机组成原理复习·3.5高速缓冲存储器
  • bootchart抓Android系统启动各阶段性能数据
  • 【微服务】Spring Cloud Alibaba 的介绍以及和主要功能
  • Type-C接口主要的几个功能引脚及功能
  • 【题目/训练】:双指针
  • 云主机部署 TiDB 测试集群
  • 景联文科技:一文详解如何构建高质量SFT数据
  • java基础03——Arrays.asList与ArrayList的区别(基本概念、用法、使用场景)
  • 24/8/17算法笔记 模仿学习算法
  • Spring中AbstractAutowireCapableBeanFactory
  • Unity3D开发之OnCollisionXXX触发条件
  • Spring Boot集成Devtools实现热更新?
  • 8.15 day bug
  • ES6指北【2】—— 箭头函数
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • Linux Process Manage
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Python_网络编程
  • ubuntu 下nginx安装 并支持https协议
  • vue学习系列(二)vue-cli
  • Webpack 4 学习01(基础配置)
  • 百度地图API标注+时间轴组件
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 通过npm或yarn自动生成vue组件
  • 通信类
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • NLPIR智能语义技术让大数据挖掘更简单
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​水经微图Web1.5.0版即将上线
  • #laravel 通过手动安装依赖PHPExcel#
  • #Z2294. 打印树的直径
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (ZT)一个美国文科博士的YardLife
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (函数)颠倒字符串顺序(C语言)
  • (九)c52学习之旅-定时器
  • (贪心) LeetCode 45. 跳跃游戏 II
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (转)c++ std::pair 与 std::make
  • (转)http-server应用
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .ai域名是什么后缀?
  • .net core 控制台应用程序读取配置文件app.config
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .NET 发展历程
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .net6 webapi log4net完整配置使用流程
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • .vue文件怎么使用_我在项目中是这样配置Vue的
  • @private @protected @public
  • @vue/cli 3.x+引入jQuery