Django的信号


Django的信号

信号是什么?

信号可以理解为Django内部的一种事件发布-订阅机制。某个事件被触发,则所有订阅和关注该事件的订阅都会接收到通知。

例如,当第三方应用关于Django应用配置发生改变的信号时:

def request_started_signal(sender, **kwargs):
    print("Request started")

class CommentConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'comment'

    def ready(self):
        """当应用启动时自动调用ready"""
        from django.core.signals import request_started

        request_started.connect(request_started_signal)

Django 的 内置信号 允许用户代码在某些操作发生时收到通知。

警告

信号看起来是松散耦合的表现,但它们很快会导致难以理解、调整和调试的代码。

在可能的情况下,你应该选择直接调用处理代码,而不是通过信号进行分发。

信号的订阅和接收

request_started.connect(request_started_signal)可以将信号订阅到一个本地方法,在信号被触发时,自动调用该方法。

另外一种订阅方式是使用 receiver() 装饰器:

from django.core.signals import request_finished
from django.dispatch import receiver


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

request_started_signal函数接收一个 sender 参数以及关键字参数 (**kwargs);所有信号处理程序都必须接受这些参数。

只订阅特定发送者的信号

仔细考虑 django.db.models.signals.pre_save 在模型保存之前发送的信号。假如你只想知道某个 特定 模型何时被保存。

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): ...

订阅时指定sender参数,可以将订阅限制在特定发送者信号。

防止重复订阅

from django.core.signals import request_finished

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

订阅时指定dispatch_uid参数,可以将订阅限制在一次中。

定义、触发和取消订阅

所有的信号都是 django.dispatch.Signal 的实例。

例如:

import django.dispatch

pizza_done = django.dispatch.Signal()

class PizzaStore:
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)

这声明了一个 pizza_done 信号,并使用send触发信号。

要从信号中断开接收者,调用 Signal.disconnect()