Django 信号#

django自带一套信号机制来帮助我们在框架的不同位置之间传递信息。也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)发送给一组接受者(receivers)。

也就是观察者模式,又叫发布-订阅(Publish/Subscribe)。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

信号系统包含以下三要素:

  • 发送者-信号的发出方
  • 信号-信号本身
  • 接收者-信号的接受者

Django内置的信号

  1. Model signals
    1. django.db.models.signals.pre_save 在某个Model保存之前调用
    2. django.db.models.signals.post_save 在某个Model保存之后调用
    3. django.db.models.signals.pre_delete 在某个Model删除之前调用
    4. django.db.models.signals.post_delete 在某个Model删除之后调用
    5. django.db.models.signals.pre_init 在某个Model实例化__init__()方法执行前调用
    6. django.db.models.signals.post_init 在某个Model实例化__init__()方法执行后调用
    7. django.core.signals.m2m_changed 在某个Model实例上更改了ManyToManyField时发送
  2. Management signals
    1. django.core.signals.pre_migrate 在某个app更新(migrate)前发送
    2. django.core.signals.post_migrate 在某个app更新(migrate)后发送
  3. Request/response signals
    1. django.core.signals.request_started 在建立Http请求时发送
    2. django.core.signals.request_finished 在关闭Http请求时发送
    3. django.core.signals.got_request_exception 在请求异常时发送
  4. Test signals
    1. setting_changed 使用test测试修改配置文件时,自动触发
    2. template_rendered 使用test测试渲染模板时,自动触发
  5. Database Wrappers
    1. connection_created 创建数据库连接时,自动触发

对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数

Copy
def my_callback(sender, **kwargs):
print("Request finished!") # 方法一:
from django.core.signals import request_finished request_finished.connect(my_callback) # 方法二:
from django.core.signals import request_finished
from django.dispatch import receiver @receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")

监听信号#

要接收信号,请使用Signal.connect()方法注册一个接收器。当信号发送后,会调用这个接收器。

方法原型:

Copy
Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)[source]

参数:

Copy
receiver :当前信号连接的回调函数,也就是处理信号的函数。
sender :指定从哪个发送方接收信号。
weak : 是否弱引用
dispatch_uid :信号接收器的唯一标识符,以防信号多次发送。

下面以如何接收每次HTTP请求结束后发送的信号为例,连接到Django内置的现成的request_finished信号。

1. 编写接收器#

接收器其实就是一个Python函数或者方法:

Copy
def my_callback(sender, **kwargs):
print("Request finished!")

请注意,所有的接收器都必须接收一个sender参数和一个**kwargs通配符参数。

2. 连接接收器#

有两种方法可以连接接收器,一种是下面的手动方式:

Copy
from django.core.signals import request_finished

request_finished.connect(my_callback)

另一种是使用receiver()装饰器:

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

3. 接收特定发送者的信号#

一个信号接收器,通常不需要接收所有的信号,只需要接收特定发送者发来的信号,所以需要在sender参数中,指定发送方。下面的例子,只接收MyModel模型的实例保存前的信号。

Copy
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel @receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
pass

4. 防止重复信号#

为了防止重复信号,可以设置dispatch_uid参数来标识你的接收器,标识符通常是一个字符串,如下所示:

Copy
from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

最后的结果是,对于每个唯一的dispatch_uid值,你的接收器都只绑定到信号一次。

自定义信号#

除了Django为我们提供的内置信号(比如前面列举的那些),很多时候,我们需要自己定义信号。

类原型:class Signal(providing_args=list)[source]

所有的信号都是django.dispatch.Signal的实例。providing_args参数是一个列表,由信号将提供给监听者的参数的名称组成。可以在任何时候修改providing_args参数列表。

下面定义了一个新信号:

Copy
import django.dispatch

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

上面的例子定义了pizza_done信号,它向接受者提供size和toppings 参数。

发送信号#

Django中有两种方法用于发送信号。

Copy
Signal.send(sender, **kwargs)[source]

Signal.send_robust(sender,** kwargs)[source] 

必须提供sender参数(大部分情况下是一个类名),并且可以提供任意数量的其他关键字参数。

例如,这样来发送前面的pizza_done信号:

Copy
import django.dispatch

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

class PizzaStore(object):
... def send_pizza(self, toppings, size):
pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
...

send()send_robust()返回一个元组对的列表[(receiver, response), ... ],表示接收器和响应值二元元组的列表。

断开信号#

方法:

Copy
Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)[source]

Signal.disconnect()用来断开信号的接收器。和Signal.connect()中的参数相同。如果接收器成功断开,返回True,否则返回False。

信号使用实例#

信号可能不太好理解,下面我在Django内编写一个例子示范一下:

urls.py

Copy
from django.conf.urls import url
from django.contrib import admin
from signal_demo import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^signal/', views.signal_view),
]

views.py

Copy
from django.dispatch import receiver, Signal
from django.shortcuts import HttpResponse
import time # 自定义信号
my_signal = Signal(providing_args=['path', 'time']) def signal_view(request):
# 接受到请求,发送信号
res = my_signal.send(signal_view, path=request.path, time=time.strftime("%Y-%m-%d %H:%M:%S"))
# 返回一个元组对的列表`[(receiver, response), ... ],表示接收器和响应值二元元组的列表
print(res)
return HttpResponse('200,ok') @receiver(my_signal, sender=signal_view)
def my_callback(sender, **kwargs):
print("我在%s时间收到来自%s的信号,请求url为%s" % (kwargs['time'], sender, kwargs["path"]))
return 'ok'

启动Django服务

访问 http://127.0.0.1:8000/signal/

console打印

Copy
[XX] "GET /signal/ HTTP/1.1" 200 6
我在XXX时间收到来自<function signal_view at 0x000001FA31DFCD08>的信号,请求url为/signal/
[(<function my_callback at 0x000001FA31E20378>, 'ok')]

Django 信号原理,源码分析#

观察者模式,又叫发布-订阅(Publish/Subscribe)。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

DJango实现信号的原理是: 回调函数,串行执行

  1. 发送者 发送 信号
  2. 信号 处理,回调 接收者
  3. 接收者处理
  4. 信号拿到接收者的返回值
  5. 发送者拿到信号的返回值(就是接收者的返回值)

参考#

  1. 官方文档
  2. Django的信号机制
  3. 信号 signal
  4. Django中的信号

Django信号机制相关解释与示例的更多相关文章

  1. django信号机制 (每个操作前后django都预留了两个钩子,便于统一化添加功能)

    信号 Django中提供了"信号调度",用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. 典型应用场景:在所有数据库相关操作(读/ ...

  2. 3分钟看懂Python后端必须知道的Django的信号机制!

    概念 django自带一套信号机制来帮助我们在框架的不同位置之间传递信息.也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)发送给一组接受者( ...

  3. Django的信号机制

    Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) .当发生一些动作的时候,发出信号,然后监听了这个信号的callback函数就会执行. Djang ...

  4. Django的信号机制详解

    Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) .当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行. Django内置了一些信号 ...

  5. Django 之 信号机制

    Django 之 信号机制 Django提供一种信号机制.其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) . 当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行 ...

  6. django 内置“信号”机制和自定义方法

    一.引子 在操作数据的时候,假设我们需要记录一些日志,这个时候,我们需要用什么来显示这个需求呢?装饰器?装饰器只能先实现整体的操作.在django 里面有这么一个东西--信号 下面我们就来了解了解它. ...

  7. Django 信号signal

    序言 Django自带一套信号机制来帮助我们在框架的不同应用位置之间传递信息.也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将信号(signals)发送给一组接收者(r ...

  8. Linux信号机制

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  9. 信号(Django信号、Flask信号、Scrapy信号)

    简介 Django.Flask.scrapy都包含了一个“信号分配器”,使得当一些动作在框架的其他地方发生的时候,解耦的应用可以得到提醒. 通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒 ...

随机推荐

  1. CSS3(2)--- 过渡(transition)

    CSS3(2)--- 过渡(transition) 一.概念 1.什么是过渡 通俗理解 是从一个状态 渐渐的过渡到 另外一个状态. 比如一个盒子原先宽度为100px,当鼠标点击时盒子的宽度变成200p ...

  2. 105道BAT最新Java面试题(MySQL+Redis+nginx+ookeeper+MongoDB)

    MySQL面试题 1. 主键 超键 候选键 外键 2.数据库事务的四个特性及含义 3. 视图的作用,视图可以更改么? 4. drop,delete与truncate的区别 5. 索引的工作原理及其种类 ...

  3. 冒泡排序(表格说明)(js)

    冒泡排序我自己的理解是(假设从大到小): 比较每一对相邻元素的值,如果前面的元素小于后面的元素那么就将它们交换过来,每次排序的比较次数逐次递减,最后的比较次数为1.总的排序轮数为数组长度减1.为了便于 ...

  4. 面试 3-5年Java开发后的感受

    在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间.我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面 ...

  5. Docker图形化工具Portainer详解

    一.介绍 说明:   Portainer是易于使用的软件,可为软件开发人员和IT操作人员提供直观的界面.   Portainer为你提供Docker环境的详细概述,并允许你管理容器,镜像,网络和数据卷 ...

  6. GIS面试小知识点

    1.什么是地理信息系统?简述其基本功能 它是随着地理科学.计算机技术.遥感技术和信息科学的发展而产生的一门科学.就应用而言,是对空间数据进行  组织.管理.分析.显示  的系统.其实本质上它探讨的就是 ...

  7. 内网渗透教程大纲v1.0

    内网渗透 ☉MS14-068(CVE-2014-6324)域控提权利用及原理解析 ☉域控权限提升PTH攻击 未完待续...

  8. 常见SQL编写和优化

    常见的SQL优化方式 对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by 涉及的列上建立索引. 应尽量避免在 where 子句中对字段进行null 值判断,否则将导致引擎放弃 ...

  9. rest.css解决不同浏览器元素默认样式不同的问题

    html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, ...

  10. js的动态表格的增删改查完整代码

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...