1. 信号定义

django包含有一个“信号分发器”,在框架内任何时候,在任何地方,有动作发生时,用来帮助解耦应用之间获取通知。简言之,信号允许特定的发送者通知一系列接收者某一特定动作已经发生了。特别有用的地方在于:许多代码片段对于同样的事件感兴趣。

2. 内建信号

django提供了许多内建的信号,这样用户代码能够在django自身的一些特定动作发生时得到通知。如下:

  • django.db.models.singals.pre_save、django.db.models.signals.post_save:在模型的save()方法被调用之前、之后发送该信号。
  • django.db.models.signals.pre_delete、django.db.models.signals.post_delete:在模型的delete()方法被调用之前、之后发送该信号。
  • django.db.models.signals.m2m_chagned:当一个ManyToManyField模型发送修改是发送该信号。
  • django.core.signals.request_started、django.core.signals.request_finished:在django开始、完成一个HTTP请求时发送该信息。
  • 等等其他信号。

3. 监听信号

为了接收一个信号,使用Signal.connect()方法来注册一个信号接收函数,当信号被发送的时候接收函数将被调用。函数接口如下:

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)

参数说明:
receiver: 回调函数,将被连接到对象的信号上。receiver函数有它的实现要求
sender: 指定一个特定的发送者,明确信号从哪里来的。
weak: django存储信号处理器默认作为弱引用。可以通过设置weak=False来修改这一行为。
dispatch_uid: 信号接收者的唯一标识,以免重复信号被发送。 例如:request_finished就是一个Signal对象,下面这行代码完成了信号的监听
request_finished.connect(my_callback) 下面的函数定义,完成了接收函数的定义
def my_callback(sender, **kwargs):
print("Request finished!")

3.1. 接收函数

接收函数可以是任意Python函数或方法:接收一个sender位置参数,一个通配的kwargs关键字参数,所有信号处理器必须接收这些参数。所有的信号发生kwargs参数,并且可能在任一时间改变这些关键字参数。根据request_finished信号文档说明,它不会发送任何参数,看似上面的回调函数也可能不传递关键字参数,但是这样的操作是错误的,如果你真的这样做,django会抛出一个错误的。

3.2. 连接接收函数

两种方式可以将一个接收者连接到信号上去。

# 1. 手动连接
from django.core.signals import request_finished def my_callback(sender, **kwargs):
print("Request finished!")
request_finished.connect(my_callback) # 2. 使用 receiver 装饰器连接
from django.core.signals import request_finished
from django.dispatch import receiver @receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")

现在my_callback函数会在每次完成完成一次请求之后被调用。

3.3. 连接信号:指定发送者

指定发送者的目的是缩小事件的监听范围,比如pre_save()信号,多数情况下只是想知道某一个特定的模型上发生的这一信号,而不是所有的模型。这时候就可以指定你所关心的sender,比如sender=User,那么只有当User模型在pre_save信号发送时,才调用receiver函数。不同的信号,能够接收的sender参数是值不同,需要根据信号文档描述进行设置,不能乱猜哦!

from django.core.signals import pre_save
from django.dispatch import receiver
from myapp.models import User @receiver(pre_save, sender=User)
def my_handler(sender, **kwargs):
print("pre_save happen in User.")

3.4. 阻止重复信号

在一些特定的情形下,连接在信号上的接收函数可能被运行多次,这可能导致你的接收函数被注册多次,并且这也就导致了同一信号事件发生时接收函数被调用多次。如果这样的行为导致问题(比如:当一个模型存在save操作是,使用信号来发送邮件通知),传递一个唯一标识符来来标识你的接收函数避免这样的情况(dispatch_uid),这个标识符通常使用字符串(其实可以使用任一可hash的对象)。最终结果是信号接收函数只会绑定一次。

from django.core.signals import request_finished

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

4. 定义和发送信号

4.1. 定义信号

所有信号都是django.dispatch.Signal的实例,providing_args是一个由参数名组成的列表,将由信号提供给监听者。

import django.dispatch

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

声明了pizza_done信号,将提供toppings、size两个参数给接收者。
注:你可以在任何时候修改这个providing_args列表,所有没必要在第一个确保参数的正确。

4.2. 发送信号

两种方式发送信号:

  • Signal.send(sender, **kwargs): 所有内建信号都是采用这个方式来发送的。
  • Signal.send_robust(sender, **kwargs):

两种方式都需要一个sender作为参数(多数时候是一个类),并且可能提供其他你所想要的关键字参数。如下发送描述怎样发送一个pizza_done信号:

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

send、send_robust都返回一个元祖对构成的列表:[ (receiver, response), ...],呈现一个调用了的接收函数和它们的response值。send比send_robust区别的地方在于由接收函数抛出的异常时如何被处理的。send不会捕捉任何由receiver函数抛出的异常,它简单的允许异常被冒泡传递。这也是当一个信号内部遇到错误时,不是所以的接收这都将被通知的原因。send_robust会使用python Exception这个比较顶层的异常类来捕捉所有的错误,并且确保所有的接收者都被通知到,错误被存放在__traceback__属性中。

5. 断开信号

Signal.disconnect(receiver=None, sender=None, dispatch_uid=None),参数与在Signal.connect()中描述的一样,返回:True断开成功,False断开失败。如果dispatch_uid被使用的时候,receiver可以传递None。

6. 内建信号

# 1. 模型信号
pre_init post_init pre_save post_save
pre_delete post_delete m2m_chagned class_prepared # 2. 管理信号
pre_migrate post_migrate # 3. 请求、响应信号
request_started request_finished get_request_exception # 4. 测试信号
setting_changed template_rendered # 5. 数据库包装器
connection_created

7. 信号注册地

可以放在AppConfig类中,AppConfig类提供了一个ready函数,这个函数的执行是由Django框架自动调用的,调用的时机是当所有的(INSTALLED_APPS)都被注册完成后。

# 介绍文档:API Reference#Applications.
from django.db.models.signals import pre_save class PollsConfig(AppConfig):
name = 'polls' def ready(self):
from .models import MyModel
# 或者:
# MyModel= self.get_model('MyModel')
pre_save.connect(receiver, sender='app_label.MyModel')

[TimLinux] Django 信号的更多相关文章

  1. Django 信号signal

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

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

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

  3. Django信号机制相关解释与示例

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

  4. Django 信号使用问题

    Django 信号使用问题: 在使用django内置信号修改新注册的用户密码的时候,发现内置信号没有被触发.百度&官方文档找到了答案 1.信号的函数应该放在哪里? 这段代码应该放在哪里? 严格 ...

  5. flask,scrapy,django信号

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

  6. pythonのdjango 信号

    一.内置信号 Django中提供了“信号调度”,用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. Model signals pre_init # d ...

  7. django信号浅谈

    Django中提供了“信号调度”,用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. 1.Django内置信号 Model signals pre_in ...

  8. django信号

    什么是信号? 信号是在某个操作前或后自动触发一些操作. 信号是通知,是一种状态,相当于在某种状态下发特定的消息 --为了实现代码层解耦 村长博客:http://www.cnblogs.com/legu ...

  9. Django 信号

    信号 Django 提供一个“信号分发器”,允许解耦的应用在框架的其它地方发生操作时会被通知到. 简单来说,信号允许特定的sender通知一组receiver某些操作已经发生. 这在多处代码和同一事件 ...

随机推荐

  1. 小白历险记:spingboot之helloworld

    还记得入职第一天的时候,先安装了相关的软件,配置了环境.boss叫我写的第一个程序:搭建一个springboot工程,输出helloworld. 哈哈话不多说,回忆一下. 1.打开IDEA,点击Cre ...

  2. 一张图讲解最少机器搭建FastDFS高可用分布式集群安装说明

     很幸运参与零售云快消平台的公有云搭建及孵化项目.零售云快消平台源于零售云家电3C平台私有项目,是与公司业务强耦合的.为了适用于全场景全品类平台,集团要求项目平台化,我们抢先并承担了此任务.并由我来主 ...

  3. U盘安装centos7 系统卡在 starting dracut initqueue hook

    U盘安装centos7启动过程中出现: [ok] Reached target Basic System 或者 [ok] starting dracut initqueue hook 下面是我解决的过 ...

  4. 创建OData Service(基于ASP.NET 4.6.1, EF 6),Part I:Project initialize

    由于ASP.NET Core 1处于RC阶段,加上OData WebAPI 对ASP.NET Core 1的跟进不是很积极,基于ASP.NET Core 1的Alpha 1版本已经N月没有check ...

  5. ubuntu 18 怎样对Windows进行远程桌面控制

    ubuntu 18 怎样对Windows进行远程桌面控制: 1. 先安装一个redesktop 工具(sudo apt-get install redesktop) 2. 在通过 redesktop ...

  6. nyoj 168-房间安排 (贪心)

    168-房间安排 内存限制:64MB 时间限制:3000ms 特判: No 通过数:33 提交数:71 难度:2 题目描述: 2010年上海世界博览会(Expo2010),是第41届世界博览会.于20 ...

  7. ENS中文文档系列之一 [ ENS介绍 ]

    前言 ENS中文文档是由我照ENS英文官方文档翻译而来,其中的一些内容和细节得到了ENS官方团队的指导.文档中包含 “LBB译注” 的地方是译者为了便于读者理解而进行的注释. 未来一段时间,我会在该博 ...

  8. Sequelize小记

    http://docs.sequelizejs.com/   官方英文 Object-Relational Mapping 增 Model.create({field1:'a', field2:'b' ...

  9. PHP 核心特性之匿名函数

    提出 在匿名函数出现之前,所有的函数都需要先命名才能使用 1 2 3 4 5 function increment($value) {     return $value + 1; } array_m ...

  10. Android中常见的设计模式

    前言: Android开发的设计模式,基本设计思想源于java的设计模式,java的设计模式有N多种,据不完全统计,迄今为止,网络出现最频繁的大概有23种.Java只是一门开发语言,学会并掌握这门语言 ...