This page looks best with JavaScript enabled

Django Signals

 ·  ☕ 3 min read

1. Basic Concepts

Django ships with a signal dispatcher built in. Signals help decouple program modules. When an event occurs elsewhere in the application, a designated function is notified. Signals let certain senders notify a group of receivers that some action has taken place.

2. Using Signals

2.1 Declaring a Signal

Before using a signal, you first have to create a signal instance and declare the list of arguments the signal receives. django.dispatch.Signal is the signal class Django provides; its constructor takes one argument, providing_args, which specifies the arguments the signal contains.

1
2
3
 from django.dispatch import Signal
# 声明一个名为mysignal的信号实例
 mysignal=Signal(providing_args=['user'])

2.2 Sending a Signal

When a receiver needs to be notified to handle a signal, the sender first has to send a signal. The Signal class provides two methods for sending signals.

1
2
Signal.send(sender, **named)
Signal.send_robust(sender, **named)

Both methods return a list of tuples [(receiver, response), … ] representing all the receiver functions and their response values. The difference lies in exception handling: send( ) does not catch exceptions raised by receivers, whereas send_robust( ) does.

1
2
3
4
 def home(request):
     mysignal.send(sender=None,user=request.user)
     # send方法第一个参数为sender,可以是对象.__class__、self、直接类名
     return HttpResponseNotAllowed('')

2.3 Associating Handler Functions

The first way is to use the connect method.

1
Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)
  • receiver: the receiver of the signal
  • sender: the sender of the signal
  • weak: by default Django stores signal handlers as weak references. As a result, if the receiver function is a local function, it may be garbage collected. To prevent this, specify weak=False.
  • dispatch_uid: the unique identifier of the signal handler, for cases where the signal may be sent repeatedly Define a receiver (which you could also call a call_back function):
1
 mysignal.connect(record)

The second way is to use a decorator.

1
2
3
4
5
6
 from django.dispatch import receiver

 @receiver(mysignal)
 def record(sender,user,**kwargs):
     #执行函数第一个参数为sender
     print user.username

Decorating with the decorator lets you designate the signal’s handler function. receiver also accepts a sender argument, handling only signals from the designated sender.

The third way is to use the dispatcher.

1
2
3
from django.db.models.signals import post_save
from django.dispatch import dispatcher
dispatcher.connect(receiver=record, signal=post_save, sender=Mymodel)

dispatcher explicitly points out the handler function, the signal, and the sender.

2.3 Handling Signals

Handling a signal is done by calling the handler function.

1
2
def callback_func(sender, **kwargs):
    pass

All signal handler functions must accept a sender argument and wildcard keyword arguments (**kwargs)

2.4 Disconnecting a Signal

1
Signal.disconnect(receiver=None, sender=None, weak=True, dispatch_uid=None):

If the receiver disconnects successfully, it returns True; otherwise it returns False.

3. Django Built-in Signals

Django’s built-in signals are already-instantiated Signal classes. When you use them, the two steps of declaring a signal and sending a signal are skipped. Simply associate a Django built-in signal directly with a custom handler function and you can use it. Below is the list of Django built-in signals:

django.db.models.signals

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
    pre_syncdb                 # 执行syncdb命令前,自动触发
    post_syncdb               # 执行syncdb命令后,自动触发

django.core.signals

1
2
3
4
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
    setting_changed        # settings发生改变时,自动触发

django.test.signals

1
    template_rendered           # 使用test测试渲染模板时,自动触发

django.db.backends.signals

1
    connection_created          # 创建数据库连接时,自动触发

For example, if you need to perform some operation after each request finishes, you can write it like this:

1
2
3
4
5
from django.core.signals import request_finished
from django.dispatch import receiver
    @receiver(request_finished)
    def callback_func(sender,**kwargs):
        print('request finished')

4. References

  • 1.http://python.usyiyi.cn/translate/django_182/topics/signals.html
  • 2.http://lilongzi.blog.51cto.com/5519072/1906557

微信公众号
WRITTEN BY
微信公众号