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 面向对象小练习

    定义MySQL类 对象有id.host.port三个属性 定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一 提供两种实例化方式,方式一:用户传入host和port 方式二:从 ...

  2. Python3 函数实践之简易购物系统

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

  3. Ambari 自定义服务集成原理介绍

    之前,在 github 上开源了 ambari-Kylin 项目,可离线部署,支持 hdp 2.6+ 及 hdp 3.0+ .github 地址为:https://github.com/8418090 ...

  4. 异常日志文件errorlong

    #region log ////////////////////use/////////////// /// <summary> /// 异常日志 /// </summary> ...

  5. C# WPF抽屉效果实现(C# WPF Material Design UI: Navigation Drawer & PopUp Menu)

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  6. 如何"快准狠"找到内存相关的问题

    为了迅速定位内存问题,通常会先运行几个覆盖面比较大的性能工具,比如 free.top.vmstat.pidstat 等. 具体的分析思路主要有这几步 先用 free 和 top,查看系统整体的内存使用 ...

  7. HttpRunner学习4--使用正则表达式提取数据

    前言 在HttpRunner中,我们可通过extract提取数据,当响应结果为 JSON 结构,可使用 content 结合 . 运算符的方式,如 content.code,用起来十分方便,但如果响应 ...

  8. 从《彩色圆环》一题探讨一类环上dp的解法

    清橙A1202 bzoj2201 bsoj4074 试题来源 2010中国国家集训队命题答辩 问题描述 小A喜欢收集宝物.一天他得到了一个圆环,圆环上有N颗彩色宝石,闪闪发光.小A很爱惜这个圆环,天天 ...

  9. java对象的实例化过程

    简单类对象的实例化过程 1.在方法区加载类: 2.在栈内存申请空间,声明变量P: 3.在堆内存中开辟空间,分配对象地址: 4.在对象空间中,对对象的属性进行默认初始化,类成员变量显示初始化: 5.构造 ...

  10. 守护线程,需要通过调用线程方法:setDaemon(boolean on)来进行设置

    package seday08.thread;/*** @author xingsir * 守护线程又称为后台线程,默认创建出来的线程都是普通线程, 守护线程需要通过调用线程方法:setDaemon( ...