Django Signals 从实践到源码分析(转)
原文:http://foofish.net/blog/66/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 sender
print kwargs
print("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 Signal request_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:
pass
signals.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 responses for 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,比如:
django.db.models.signals.presave & django.db.models.signals.postsave
Sent before or after a model’s save() method is called.
django.db.models.signals.predelete & django.db.models.signals.postdelete
Sent before or after a model’s delete() method or queryset’s delete() method is called.
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就会忽略掉。
完!
Django Signals 从实践到源码分析(转)的更多相关文章
- Django的settings文件部分源码分析
Django的settings文件部分源码分析 在编写Django项目的过程中, 其中一个非常强大的功能就是我们可以在settings文件配置许多选项来完成我们预期的功能, 并且这些配置还必须大写, ...
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- Django——基于类的视图源码分析 二
源码分析 抽象类和常用视图(base.py) 这个文件包含视图的顶级抽象类(View),基于模板的工具类(TemplateResponseMixin),模板视图(TemplateView)和重定向视图 ...
- Django REST framework —— 认证组件源码分析
我在前面的博客里已经讲过了,我们一般编写API的时候用的方式 class CoursesView(ViewSetMixin,APIView): pass 这种方式的有点是,灵活性比较大,可以根据自己的 ...
- Django(60)Django内置User模型源码分析及自定义User
前言 Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了.它的完整的路径是在django.contrib.auth.models.User. User模型源码分析 ...
- django的RestFramework模块的源码分析
一.APIView源码分析 查看源码的前提要知道,找函数方法必须先在自己的类中找,没有再往父类找,一层一层网上找,不能直接按ctrl点击 在我们自己定义的类中没有as_view方法的函数,所以肯定是继 ...
- Django rest framework框架——APIview源码分析
一.什么是rest REST其实是一种组织Web服务的架构,而并不是我们想象的那样是实现Web服务的一种新的技术,更没有要求一定要使用HTTP.其目标是为了创建具有良好扩展性的分布式系统. 可用一句话 ...
- Django(55)GenericAPIView源码分析
源码分析 GenericAPIView继承自APIView,也就是在APIView基础上再做了一层封装,源码如下: class GenericAPIView(views.APIView): query ...
- Django REST framework —— 权限组件源码分析
在上一篇文章中我们已经分析了认证组件源码,我们再来看看权限组件的源码,权限组件相对容易,因为只需要返回True 和False即可 代码 class ShoppingCarView(ViewSetMix ...
随机推荐
- STL笔记(3) copy()之绝版应用
STL笔记(3) copy()之绝版应用 我选用了一个稍稍复杂一点的例子,它的大致功能是:从标准输入设备(一般是键盘)读入一些整型数据,然后对它们进行排序,最终将结果输出到标准输出设备(一般是显示器屏 ...
- 【Todo】深入理解Java虚拟机 读书笔记
有一个在线系列地址 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> http://book.2cto.com/201306/25426.html 已经下载了这本书(60多M ...
- HDU 1505 City Game
这题是上一题的升级版 关键在于条形图的构造,逐行处理输入的矩阵,遇到'F'则在上一次的条形图基础上再加1,遇到'R'则置为0 然后用上一题的算法,求每行对应条形图的最大矩阵的面积. 另外:本来是deb ...
- php里的declare用法
function tick_handler () { echo "tick_handler() called<br>" ; } function tick_handle ...
- FPGA代码设计规范整理
1.设计中的FIFO.状态机接口需要有异常恢复状态和状态上报机制,格雷码电路防止被综合电路优化掉. a)自行设计的格雷码FIFO(一般用于连续数据流跨时钟域)用Synplify综合时,为了防止被优化需 ...
- JVM——三个ClassLoader详解
类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java执行时系统组件,它负责在运行时查找和装入Class字节码文件.JVM在运行时会产生三个ClassLoader: ...
- PHP的cURL库:抓取网页,POST数据及其他,HTTP认证 抓取数据
From : http://developer.51cto.com/art/200904/121739.htm 下面是一个小例程: ﹤?php// 初始化一个 cURL 对象$curl = curl_ ...
- Memcached 内存级缓存
Memcached在大型网站中应用 memcached是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视 频.文件以及 ...
- CURL: CURLE_COULDNT_CONNECT问题探究
摘自:: 存储系统研究: socket connect error 99(Cannot assign request address) 这是最近使用libcurl写http服务的压力测试的时候遇到的 ...
- C#的Timer
PowerCoder 原文 C#的Timer 再C#里现在有3个Timer类: System.Windows.Forms.Timer System.Threading.Timer System.Tim ...