>

从实践到源码分析

- 编辑:金沙国际平台登录 -

从实践到源码分析

django——signal

事实上可以清楚为django内部的钩子,当某二个事件爆发时,另外程序会触发并对其作出有关反应,通过signal回调管理函数(receivers),进而越来越大程度的解耦我们的门类

  • 导入类库

     1 from django.shortcuts import render 2 from django.http import HttpResponse 3 from django.core.signals import request_finished,request_started,got_request_exception 4 from django.dispatch import receiver 5 from django.dispatch.dispatcher import Signal 6 from django.db.models import signals 7 from django.db.models.signals import pre_save,pre_delete 8 from django.db.models.base import Model 9 import django.dispatch10 from app.models import SomeModel
    
  • Django内置时域信号

1 @receiver(request_started)2 def requeststarted(sender,**kwargs):3     print(sender,'这是request_started')4 request_started.connect(requeststarted)#请求完成信号
  • 嵌入时域信号触发格局

    • 先定义时限信号激活时要接触的函数,然后用 实信号类型名.connect,就可以直达与第三种装饰器方法同样的法力
    • 三个receiver装饰器,里面第三个参数放时域信号的种类,第一个参数放附加参数,然后装饰时域信号激活时要接触的函数

      1 @receiver    #model保存信号2 def presave(sender,**kwargs):3     print(sender,'这是pre_save')4 5 @receiver(pre_delete)    #model删除信号6 def predelete(sender,**kwargs):7     print(sender,'这是pre_delete')
      
  • 自定义时域信号

style="width: 0px; height: 0px; visibility: hidden; margin: 0px; padding: 0px">未有放置这种实信号,客户可自定义,与内置实信号使用的第一种方法一样

1 bus_comming = django.dispatch.Signal(providing_args=['plate_numbers'])2 3 def callback(sender,**kwargs):4     print(sender,kwargs,'这是自定义信号')5 6 bus_comming.connect7 bus_comming.send(sender='lijingbo',plate_numbers=666)

原文:

当有些事件爆发的时候,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)

以后恳请一个U奥迪Q3L路线/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,比如:

  1. django.db.models.signals.presave & django.db.models.signals.postsave

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

  2. 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.

  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就能忽视掉。

完!

本文由编程发布,转载请注明来源:从实践到源码分析