浅谈Django的Signals的实现

在说Signals的实现之前,需要先了解一下发布/订阅模型

模型介绍

发布订阅是一种消息范式,消息的发送者不会将消息直接发送给特定的接收者。而是将消息发送某个频道上,无需了解哪些订阅者可能存在。同样的,订阅者可以表达对一个或多个频道的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在。

发布者

即消息的生产者。

频道

一个消息的通道,标识发布者需要将消息发送到哪一个消息通道。

订阅者

即消息接收者。

Django提供的Signals

与model有关的signals

from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.db.backends.signals import connection_created

与请求有关的signals

from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.core.signals import setting_changed

与测试有关的signals

from django.test.signals import setting_changed
from django.test.signals import template_rendered

关于signals的使用就不说明了。

Signals实现

创建一个发布者类

from typing import List, Tupleclass Signal:def __init__(self):self.receivers: List[Tuple[Tuple[int, int], callable]] = []def send(self, sender, **kwargs):return [(receiver, receiver(signal=self, sender=sender, **kwargs))for receiver in self.live_receivers(sender=sender)]def connect(self, receiver: callable, sender=None):lookup_key: Tuple[int, int] = (id(receiver), id(sender))self.receivers.append((lookup_key, receiver))def disconnect(self, receiver: callable, sender=None):lookup_key: Tuple[int, int] = (id(receiver), id(sender))self.receivers.remove((lookup_key, receiver))def live_receivers(self, sender) -> List[callable]:receivers: List[callable] = []sender_key = id(sender)for (receiver_id, sender_id), receiver in self.receivers:if sender_key == sender_id:receivers.append(receiver)return receiversdef subscribe(signal, **kwargs):def _decorator(func):if isinstance(signal, (list, tuple)):for s in signal:s.connect(func, **kwargs)else:signal.connect(func, **kwargs)return funcreturn _decorator

实例化发布者

pre_init = Signal()

实例化一个发布者,pre_init可以在初始化一个实例之前通知订阅者。

创建支持通知的一个类

class Test:def __init__(self, *args, **kwargs):cls = self.__class__pre_init.send(sender=cls, args=args, kwargs=kwargs)for key, value in kwargs.items():setattr(self, key, value)

订阅pre_intit消息

@subscribe(pre_init, sender=Model)
def test_pre_init(sender, **kwargs):print("-------pre_init_______")print(sender)print(kwargs)print("-------end_pre_init_______")

使用

Test(a=1, b=2)

这个时候便会输出test_pre_init中相应的信息

思考

First

Q

如果我有多个类都通知了pre_init,而test_pre_init只想处理某个特定的类发出的消息,应该如何实现?

A

在这个例子中,发送者就是Test类,接收者就是test_pre_init方法,消息通道则是pre_init。当执行send方法时,由pre_init来筛选需要发送给哪些接收者。接收者在注册的时候就已经指定了我要接收谁的消息。

Second

Q

pre_init筛选,时间复杂度太高,为O(n),如何降低时间复杂度。

A

可以换一种存储方式,改成dict来存储接收者。可以把时间复杂度降为O(1),也可以由接收者来控制,当消息来的时候由接收者来选择是否接收该信息。

浅谈Django的Signals的实现相关推荐

  1. 浅谈Django的中间件与Python的装饰器

    浅谈Django的中间件 与Python的装饰器 一.原理 1.装饰器是Python的一种语法应用,利用闭包的原理去更改一个函数的功能,即让一个函数执行之前先到另外一个函数中执行其他需求语句,在执行该 ...

  2. 用python前端html后端django_浅谈Django前端后端值传递问题

    前端后端传值问题总结 前端传给后端 通过表单传值 1.通过表单get请求传值 在前端当通过get的方式传值时,表单中的标签的name值将会被当做action的地址的参数 此时,在后端可以通过get请求 ...

  3. 浅谈web开发以及django的安装和入门

    浅谈web开发 1.B/S和C/S结构 B/S:浏览器与服务器进行的交互模式(不需要官方下载的,一夫多妻制) C/S:客户机与服务器进项的交互模式(必须官方下载的,一夫一妻制 2.MVC和MVT MV ...

  4. 浅谈Python Web的五大框架

    说到web framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全列表见:http://wi ...

  5. 浅谈压缩感知(二十一):压缩感知重构算法之正交匹配追踪(OMP)

    主要内容: OMP的算法流程 OMP的MATLAB实现 一维信号的实验与结果 测量数M与重构成功概率关系的实验与结果 稀疏度K与重构成功概率关系的实验与结果 一.OMP的算法流程 二.OMP的MATL ...

  6. 浅谈python_浅谈python-Django

    浅谈 python-Django 鲁去非 湖北大学知行学院 [摘 要] 摘要:作为 Web 框架, Django 基于 MVT 分为三大块,模型 model ,视图 view ,模板 template ...

  7. 浅谈五大Python Web框架

    http://www.csdn.net/article/2011-02-17/292058 导读:作者飞龙写了一篇<浅谈Python Web框架>,文中他介绍了几个Python Web框架 ...

  8. python脚本开头怎么写_浅谈Python脚本开头及导包注释自动添加方法

    浅谈Python脚本开头及导包注释自动添加方法 1.开头:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定 #!/usr/bin/python 是用来 ...

  9. 浅谈运维工程师的开发能力的培养

    写在前面 本文已获得作者授权,作者的博客地址:https://www.cuiliangblog.cn/ 原文链接:浅谈运维工程师的开发能力的培养 一.运维工程师发展路线 1. 传统运维 侧重点是解决具 ...

最新文章

  1. php 点击表头排序,TP5+ajax实现点击表格表头切换排序,带分页
  2. javascript之DOM编程正则表达式引入
  3. 关于编码ansi、GB2312、unicode与utf-8的区别
  4. 图片image和byte处理,fileupload上传图片
  5. VC6获取硬盘序列号、型号、修订版本号
  6. [Java] 如何学Java
  7. lua里面的客户端服务器协议,Lua 服务器与客户端实例(转)
  8. (10)FPGA专业术语(第2天)
  9. win10的ios镜像
  10. MIPI接口和DVP接口摄像头学习笔记
  11. USB3300速度调试
  12. Oracle 函数编写
  13. 计算机computer英语划分音节,computer是什么意思
  14. MP地面站二次开发教程(四)地面站优化及其功能测试
  15. ubuntu操音量调整命令amixer
  16. 手把手带你爬取猫眼电影,正则解析
  17. 项目经理常用的几大项目管理工具盘点
  18. 超经典爆笑的人生格言
  19. python可变数据类型和不可变数据类型_python 可变数据类型和不可变数据类型
  20. AB PLC协议开发总结

热门文章

  1. 玩转Windows服务系列——Windows服务小技巧
  2. 学物理难还是学计算机难,数学专业,物理专业和计算机专业怎么选择?哪一个未来前景比较好呢?...
  3. Python 自动化带你轻松赚钱
  4. Verilog学习脚印2-时序逻辑
  5. 快盘做网站服务器,搭建基于金山快盘的Git服务器
  6. 石器时代单机版 – 80后的初恋网游
  7. Similarity and Matching of Neural Network Representations 论文阅读笔记
  8. Android自定义图片拼图游戏
  9. centos 温度监控软件
  10. matlab振动函数代码,Matlab振动程序-代码作业.docx