###Signals是什么

为了回答这个问题,我们先来看下django官网对它的描述:

Django includes a “signal dispatcher” which helps allow decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events.

大概意思是说:Django内部包含了一位“信号调度员”:当某事件在框架内发生时,它可以通知到我们的应用程序(处理函数)。 简而言之,当event(事件)发生时,signals(信号)允许若干 senders(发送者)通知一组 receivers(接收者)。

很像js的事件驱动模型。关于事件驱动,我在上一篇文章中有谈论,这里不多说。

###有什么用的

在web开发中, 你可能会遇到下面这种场景:

在用户完成某个操作后, 自动去执行一些后续的操作. 譬如用户完成修改密码后, 你要发送一份确认邮件.

如果一个操作可能会触发多个后续事件, 此时使用signals会非常方便. 我们可以想要一下应用场景:

  • sns中的事件通知, 如用户发表了一篇博文, 然后通知所有的好友
  • 用户信息的更改的邮件通知
  • 用户订制信息的邮件通知等

###如何使用

####常用的信号集:

  • django.db.models.signals.pre_save model在save()前发送的信号
  • django.db.models.signals.post_save model在save()后发送的信号
  • django.db.models.signals.pre_delete
  • django.db.models.signals.post_delete

####来自官网的例子

1
2
3
4
5
6
7
#使用装饰器
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")

Connecting to signals sent by specific senders.

就是说我们只处理某个模型发出的信号

1
2
3
4
5
6
7
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):
    ...

####自定义事件 在此使用一休哥同学给的例子,也是Django中现成的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#file:django\db\models\signals.py

from django.dispatch import Signal
post_syncdb = Signal(providing_args=["class", "app", "created_models", 
"verbosity", "interactive"])

#-----------------------------------

#file:django\contrib\contenttypes\management.py

from django.db.models import signals
signals.post_syncdb.connect(update_contenttypes)

#-----------------------------------
#file:django\core\management\sql.py

def emit_post_sync_signal(created_models, verbosity, interactive, db):
    # Emit the post_sync signal for every application.
    for app in models.get_apps():
        app_name = app.__name__.split('.')[-2]
        if verbosity >= 2:
            print("Running post-sync handlers for application %s" % app_name)
        models.signals.post_syncdb.send(sender=app, app=app,
            created_models=created_models, verbosity=verbosity,
            interactive=interactive, db=db)

更具体的实例可以参考:django拾遗之signal

###参考 * django官网 * 浅谈django的信号机制 Signals * django拾遗之signal