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
  1. def my_callback(sender, **kwargs):
  2. print("Request finished!")
  3. # 方法一:
  4. from django.core.signals import request_finished
  5. request_finished.connect(my_callback)
  6. # 方法二:
  7. from django.core.signals import request_finished
  8. from django.dispatch import receiver
  9. @receiver(request_finished)
  10. def my_callback(sender, **kwargs):
  11. print("Request finished!")

监听信号#

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

方法原型:

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

参数:

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

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

1. 编写接收器#

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

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

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

2. 连接接收器#

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

Copy
  1. from django.core.signals import request_finished
  2. request_finished.connect(my_callback)

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

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

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

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

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

4. 防止重复信号#

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

Copy
  1. from django.core.signals import request_finished
  2. 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
  1. import django.dispatch
  2. pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

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

发送信号#

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

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

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

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

Copy
  1. import django.dispatch
  2. pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
  3. class PizzaStore(object):
  4. ...
  5. def send_pizza(self, toppings, size):
  6. pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
  7. ...

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

断开信号#

方法:

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

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

信号使用实例#

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

urls.py

Copy
  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from signal_demo import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^signal/', views.signal_view),
  7. ]

views.py

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

启动Django服务

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

console打印

Copy
  1. [XX] "GET /signal/ HTTP/1.1" 200 6
  2. 我在XXX时间收到来自<function signal_view at 0x000001FA31DFCD08>的信号,请求url为/signal/
  3. [(<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. Python 命令行之旅:使用 click 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  2. Spring AOP应用场景你还不知道?这篇一定要看!

    回顾一下Spring AOP的知识 为什么会有面向切面编程(AOP)? 我们知道Java是一个面向对象(OOP)的语言,但它有一些弊端,比如当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日 ...

  3. java面试题干货96-125

    这部分主要是与Java Web和Web Service相关的面试题. 96.阐述Servlet和CGI的区别? 答:Servlet与CGI的区别在于Servlet处于服务器进程中,它通过多线程方式运行 ...

  4. MySQL创建数据表时设定引擎MyISAM/InnoDB

    我在配置mysql时将配置文件中的默认存储引擎设定为了InnoDB.今天查看了MyISAM与InnoDB的区别,在该文中的第七条"MyISAM支持GIS数据,InnoDB不支持.即MyISA ...

  5. 用js写直角三角形,等腰三角形,菱形

    //一. 画一个直角三角形     // 第几行   *号数     // *        1        1       // **       2        2     // ***    ...

  6. 咪咕音乐链接歌词封面搜索等接口API

    搜索 pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?&ua=Android_migu&version=5.0.1&am ...

  7. 01-EF Core笔记之创建模型

    使用EF Core的第一步是创建数据模型,模型建的好,下班走的早.EF Core本身已经设置了一系列约定来帮我们快速的创建模型,例如表名.主键字段等,毕竟约定大于配置嘛.如果你想改变默认值,很简单,E ...

  8. Cesium案例解析(二)——ImageryLayers影像图层

    目录 1. 概述 2. 实例 2.1. ImageryLayers.html 2.2. ImageryLayers.js 2.2.1. 代码 2.2.2. 解析 3. 结果 1. 概述 Cesium支 ...

  9. 比较typeof与instanceof

    相同点: JavaScript中typeof和instanceof常用来判断一个变量是否为空,或者是什么类型的. 不同点: typeof的定义和用法: 返回值是一个字符串,用来说明变量的数据类型. 细 ...

  10. Winform项目常用配置方法

    在我们做项目的时候经常遇到需要动态配置系统的情况,比如说10台电脑装了同一个软件,需要识别唯一码,这时候我们会用到配置方法. 具体方法如下: 1) Config文件 里面增加你需要的变量,具体用法如下 ...