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. Python3 函数实践之简易购物系统

    函数实践之简易购物系统 项目主要需求: 用户可以自行选择功能 该购物系统具有注册/登录/购物/购物车/退出登录功能 用户在登录后才能使用购物/购物车/退出登录功能 ''' 注册 登录 购物 购物车 退 ...

  2. 【Web技术】281- 滴滴开源小程序框架 Mpx2.0

    滴滴Mpx框架负责人@hiyuki,滴滴出行网约车webapp乘客团队的负责人,也是滴滴开源的小程序框架Mpx的负责人和核心作者 Mpx是一款致力于提高小程序开发体验和效率的增强型小程序框架,目前在滴 ...

  3. springboot使用api操作HBase之shell

    HBase的基本读写流程写入流程读取流程HBase的模块与协作HBase启动RegionServer失效HMaster失效HBase常用的Shell命令进入shellhelp命令查询服务器状态查看所有 ...

  4. debian官网qcow2镜像修改root账号密码,开启ssh等

    1.下载官网qcow2镜像文件 wget http://172.16.20.10/vmtemplate/KVM/wangrui/Debian/debian-10.2.0-openstack-amd64 ...

  5. Vue项目中实现用户登录及token验证

    学习博客:https://www.cnblogs.com/web-record/p/9876916.html

  6. Python批量更新模块的方法【面试必学】

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:ranchlin      小编的环境为win10+python 3. ...

  7. MySql数据库之常用数据类型及常用约束简述

    本文呢,主要给大家简述一下数据库中常用的几种数据类型以及约束. 1.数据类型 数据类型,是指数据表中可以存储的数据的种类. 数据库中常用的数据类型有: 1.整型:int.bit 2.小数:decima ...

  8. 1、看源码MVC如何实例化控制器?

    我们知道MVC请求进来,然后路由匹配,然后找到控制器和Action,最后会调用Action方法,但是大家想想控制器是个普通的类,Action是个普通的实例方法,要想调用Action必须先实例化控制器, ...

  9. 使用PHP生成并导出CSV文件

    CSV文件是以纯文本形式存储的,一般以逗号为分隔符.这里主要简单介绍下如何导出CSV文件. 一.浏览器导出CSV文件格式 /** * 导出CSV文件 */ function exportCsv() { ...

  10. js的动态表格的增删改查思路

    1. 首先我们要知道,动态添加,肯定不是 在页面上写死得,而是通过js调用循环放入到页面上的,我们在写动态表格的时候不要先着急写,我们第一步要做的就是构思,要把自己的逻辑先弄清楚,不然的话,前面是好写 ...