[TimLinux] Django 信号

1. 信号定义

django包含有一个“信号分发器”,在框架内任何时候,在任何地方,有动作方式是,用来帮助解耦应用之间获取通知。简言之,信号允许特定的发送者通知一系列接收者动作已经发生了。特别有用的地方在于:许多代码片段对于同样的事件感兴趣。

2. 内建信号

django提供了许多内建的信号,这样用户代码能够在django自身的一些特定动作发生时得到通知。如下:

  • django.db.models.singals.pre_save、django.db.models.signals.post_save:在模型的save()方法被调用之前、之后发送该信号。
  • django.db.models.signals.pre_delete、django.db.models.signals.post_delete:在模型的delete()方法被调用之前、之后发送该信号。
  • django.db.models.signals.m2m_chagned:当一个ManyToManyField模型发送修改是发送该信号。
  • django.core.signals.request_started、django.core.signals.request_finished:在django开始、完成一个HTTP请求时发送该信息。
  • 等等其他信号。

3. 监听信号

为了接收一个信号,使用Signal.connect()方法来注册一个信号接收函数,当信号被发送的时候接收函数将被调用。函数接口如下:

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)

参数说明:
receiver: 回调函数,将被连接到对象的信号上。receiver函数有它的实现要求
sender: 指定一个特定的发送者,明确信号从哪里来的。
weak: django存储信号处理器默认作为弱引用。可以通过设置weak=False来修改这一行为。
dispatch_uid: 信号接收者的唯一标识,以免重复信号被发送。

例如:request_finished就是一个Signal对象,下面这行代码完成了信号的监听
request_finished.connect(my_callback)

下面的函数定义,完成了接收函数的定义
def my_callback(sender, **kwargs):
print("Request finished!")

 3.1. 接收函数

接收函数可以是任意Python函数或方法:接收一个sender位置参数,一个通配的kwargs关键字参数,所有信号处理器必须接收这些参数。所有的信号发生kwargs参数,并且可能在任一时间改变这些关键字参数。根据request_finished信号文档说明,它不会发送任何参数,看似上面的回调函数也可能不传递关键字参数,但是这样的操作是错误的,如果你真的这样做,django会抛出一个错误的。

3.2. 连接接收函数

两种方式可以将一个接收者连接到信号上去。

# 1. 手动连接
from django.core.signals import request_finished

def my_callback(sender, **kwargs):
    print("Request finished!")
request_finished.connect(my_callback)


# 2. 使用 receiver 装饰器连接
from django.core.signals import request_finished
from django.dispatch import receiver

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

现在my_callback函数会在每次完成完成一次请求之后被调用。

3.3. 连接信号:指定发送者

指定发送者的目的是缩小事件的监听范围,比如pre_save()信号,多数情况下只是想知道某一个特定的模型上发生的这一信号,而不是所有的模型。这时候就可以指定你所关心的sender,比如sender=User,那么只有当User模型在pre_save信号发送时,才调用receiver函数。不同的信号,能够接收的sender参数是值不同,需要根据信号文档描述进行设置,不能乱猜哦!

from django.core.signals import pre_save
from django.dispatch import receiver
from myapp.models import User

@receiver(pre_save, sender=User)
def my_handler(sender, **kwargs):
    print("pre_save happen in User.")

3.4. 阻止重复信号

 在一些特定的情形下,连接在信号上的接收函数可能被运行多次,这可能导致你的接收函数被注册多次,并且这也就导致了同一信号事件发生时接收函数被调用多次。如果这样的行为导致问题(比如:当一个模型存在save操作是,使用信号来发送邮件通知),传递一个唯一标识符来来标识你的接收函数避免这样的情况(dispatch_uid),这个标识符通常使用字符串(其实可以使用任一可hash的对象)。最终结果是信号接收函数只会绑定一次。

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

4. 定义和发送信号

猜你喜欢

转载自www.cnblogs.com/timlinux/p/9255427.html