django signal
来源:互联网 发布:excel多表格数据联动 编辑:程序博客网 时间:2024/05/18 21:05
django拾遗之signal
摘要
突然发现自己比较喜欢写系列类型的文章, 因为通常类似的一些文章都具有相同的特征,但 一篇很难完全覆盖,所以往往写系列的文章比较合适.
拾遗 系列的文章主要是一些 常被程序员忽略, 但 又特别有意义 的一些内容.
引入
在web开发中, 你可能会遇到下面这种场景:
在用户完成某个操作后, 自动去执行一些后续的操作. 譬如用户完成修改密码后,你要发送一份确认邮件.
当然你可以把逻辑写在一起, 但是有个问题是, 通常前置动作(触发操作)会不止一种(如用户更改了其它信息的确认邮件), 这时候这个逻辑会需要写多次, 所以你可能会想着DRY, 于是你把它写到了一个函数中,每次调用. 当然这是没问题的.
但是, 如果你换个思路你会发现另一个完全不同的方案, 即:
- 类似于daemon的程序监听着特定的事件
- 前置操作来触发相应的事件
- 监听程序执行对应的操作
这样的好处是什么呢?
- 松耦合(不用把后续操作写在主逻辑中)
- 便于复用(这也是为什么 django 本身, 及第三方应用如 pinax 大量使用此技术的原因)
在各种高级语言中都会有类似的特性,如java, javascript等.而在 django 中我们使用 signal.
本文会着重介绍 django 的 signal 相关知识.
django的signal定义
什么是signal?
django 包含一个称为 signal dispatcher, 用来解耦合框架中发生的事件与 得到通知的应用 之间的逻辑. 简单地说, 在特定事件发生时, 使用signal 发送者 能够通知一系列 接收者(一个或者多个).
python 本身没有类似机制的支持, 但是 django 基于 PyDispatcher 进行了性能 和代码结构上的优化来增加了signal功能.
如何使用django的signal
在使用signal之前,我们先了解下django signal的处理流程.
参考下图:
那么我们来逐步完成我们简单的signal.
场景
我们有2个页面 ,一个是文章显示页面,一个是文章增加页面, 文章只有title,content及is_public三个域.
我们使用signal是完成,当用户添加一个文章后,我们置其is_public=False, 我们使用signal来实现此功能.
注册signal
下面是测试用的project的文件结构,具体可以 下载源代码 来在本地运行.
.|-- __init__.py|-- __init__.pyc|-- logs| `-- filelog.log|-- manage.py|-- settings.py|-- settings.pyc|-- signal.db|-- testsignal| |-- __init__.py| |-- __init__.pyc| |-- models.py| |-- models.pyc| |-- signals.py| |-- signals.pyc| |-- templates| | |-- add.html| | |-- base.html| | `-- index.html| |-- tests.py| |-- urls.py| |-- urls.pyc| |-- views.py| `-- views.pyc|-- urls.py`-- urls.pyc
testsignal是我们建立的示例app, 我们首先要注册signal, 具体代码如下(testsignal/signals.py):
import django.dispatch delete_done = django.dispatch.Signal(providing_args=['obj'])
引入django的包, 并且注册 delete_done为我们将要使用的signal.
关联signal对应的listener
然后我们关联对应的listener, 代码如下: (testsignal/models.py)
from django.db.models.signals import pre_savefrom django.db import modelsimport loggingimport signals
# Create your models here.class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() is_public = models.BooleanField(default=True, blank=True)
def delete(self): #self.is_public = False signals.delete_done.send(sender=Article, obj=self)
def __unicode__(self): return self.title
def zhutao(sender, kwargs): logging.debug(kwargs)
if "obj" in kwargs: obj = kwargs.get("obj") logging.debug(obj.is_public) obj.is_public = False obj.save() logging.debug("signal recieved! zhutao is called.") logging.debug(obj.is_public)
signals.delete_done.connect(zhutao, sender=Article)
我们来看最后一行, signals.delete_done.connect(zhutao, sender=Article), 即将 我们上面注册的 delete_done 和 监听函数 zhutao 关联了起来, 而 这里的 sender=Article, 则是用来限制只有当Article有更新时我们才会触发这个事件.
触发监听事件
最后,我们要在特定操作发生时触发相应的监听函数, 具体代码如下(testsignal/views.py):
from django.http import HttpResponse,HttpResponseRedirectfrom django.core.urlresolvers import reversefrom django.shortcuts import render_to_responseimport signalsfrom models import *
def index(request): articles = Article.objects.all().order_by("-id") return render_to_response("index.html", {"articles":articles})
def add(request): if request.method == "POST": title = request.POST.get("title", "") content = request.POST.get("content", "") if title and content: article = Article(title=title, content=content) article.save() article.delete() return HttpResponseRedirect(reverse(index))
return render_to_response("add.html", {})
其它的只是django的普通views.py中的方法,我们主要来看 article.delete() 这行代码, 执行这个后,我们会调用models.py中的delete方法,见上面的models.py中的代码, 它会执行下面一行代码:
signals.delete_done.send(sender=Article, obj=self)
面这行代码正是向delete_done发送了事件的触发,此时,对应的监听函数 zhutao 会得到执行,
从而将 is_public 置为False.
我们的任务也得以完成.
具体的说明可以 下载源代码 来运行,你会在logs/filelog.log文件中看到对应的log输出.
示例输出为:
2009-10-27 03:28:27,202 DEBUG models.zhutao Line:26 {'signal': <django.dispatch.dispatcher.Signal object at 0x9523e4c>, 'obj': <Article: aaa>}2009-10-27 03:28:27,203 DEBUG models.zhutao Line:29 True2009-10-27 03:28:27,209 DEBUG models.zhutao Line:32 signal recieved! zhutao is called.2009-10-27 03:28:27,209 DEBUG models.zhutao Line:33 False
一些其它的应用
我们上面提到过 django, pinax 也大量地使用了signal技术,那我们下面简要看看, django 中有哪些具体的应用.
在 django 中, 主要有下面几类:
Model signals
- pre_init
- post_init
- pre_save
- post_save
- pre_delete
- post_delete
- class_prepared
Management signals
- post_syncdb
Request/response signals
- request_started
- request_finished
- got_request_exception
Test signals
- template_rendered
这些都是 django 内置的signals来方便用户来进行一些特定的操作,具体的介绍可以参考: built-in signals.
至于 pinax 可以下载其源代码来具体查看.
可能的应用场景
那么signals有哪些可能的应用场景呢?我们能够在什么样的场景下使用呢?
从定义来看,其实已经很明确了, 如果一个操作可能会触发多个后续事件, 此时使用signals会非常方便.
那么具体的应用可以考虑:
- sns中的事件通知, 如用户发表了一篇博文, 然后通知所有的好友
- 用户信息的更改的邮件通知
- 用户订制信息的邮件通知等
结论
django 的signals是非常强大的, 如果我们能够很好地使用,则能够大大地提高代码的可维护性, 复用性,以及减少耦合等.
参考资料
- django
- pinax
- Django signals
本文的rst源码
- django signal
- django signal
- django拾遗之signal
- django拾遗之signal
- django signal基础
- django拾遗之signal
- django signal 拾遗
- Django Signal 解析
- Django Signal 源码解析
- django signal使用
- 浅谈Django中的Signal
- How to stop recursion on Django's post_save signal
- signal
- signal
- Signal
- signal
- signal
- signal
- ibatis mybatis sql语句配置 符号不兼容 大于号 小于号
- S3C2440驱动移植——AT24C02(EEPROM)移植
- eclipse导入本地项目SVN信息丢失的问题
- openfire删除
- 分析产品数据时需要注意哪些坑?
- django signal
- Proxy
- 面试题 33
- ios9 - (NSUInteger)supportedInterfaceOrientations 警告
- 黑马程序员-Java基础学习第七天总结
- 关联jar包的源代码
- jboss部署web项目
- 转化流和IO流操作规律
- 关于Genymotionmotion的一些问题