信号

    Django 提供了 内置信号集 使用户代码能够获得 Django 自身某些操作的通知。其中包括一些有用的通知:

    查看 内置信号文档 以获取每个信号的完整列表和说明。

    你还可以 ;见下文。

    要接收信号,使用 Signal.connect() 方法注册一个 接收器 函数。当发送信号时调用接收器。信号的所有接收器函数都按照注册时的顺序一个接一个调用。

    (receiver, sender=None, weak=True, dispatch_uid=None)

    让我们通过注册一个在每个HTTP请求完成后被调用的信号来看看这是如何工作的。我们将连接到 request_finished 信号。

    首先,我们需要定义一个接收器函数。一个接收器可以是任何 Python 函数或方法:

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

    We’ll look at senders , but right now look at the **kwargs argument. All signals send keyword arguments, and may change those keyword arguments at any time. In the case of request_finished, it’s documented as sending no arguments, which means we might be tempted to write our signal handling as my_callback(sender).

    连接接收器函数

    有两种方法可以将接收器连接到信号。你可以选择手动连接线路:

    1. from django.core.signals import request_finished
    2. request_finished.connect(my_callback)

    或者,你可以使用一个 receiver() 装饰器:

    receiver(signal)

    参数:signal — 一个用于连接函数的信号或包含多个信号的列表。

    以下是你如何使用装饰器连接:

    现在,我们的 my_callback 函数将在每次请求完成时被调用。

    我的代码该放在哪?

    严格来说,信号处理和注册的代码可以放在任何你喜欢的地方,但是推荐避免放在应用程序的根目录和 models 模块内以尽量减少导入代码的副作用。

    In practice, signal handlers are usually defined in a signals submodule of the application they relate to. Signal receivers are connected in the ready() method of your application . If you’re using the receiver() decorator, import the signals submodule inside , this will implicitly connect signal handlers:

    1. from django.apps import AppConfig
    2. from django.core.signals import request_finished
    3. class MyAppConfig(AppConfig):
    4. ...
    5. # Implicitly connect a signal handlers decorated with @receiver.
    6. from . import signals
    7. # Explicitly connect a signal handler.
    8. request_finished.connect(signals.my_callback)

    注解

    ready() 方法在测试过程中可能会多次执行,因此你可能需要 ,尤其是当您计划在测试中发送信号时。

    有些信号被多次发送,但你只对接收这些信号的某个子集感兴趣。例如,仔细考虑 django.db.models.signals.pre_save 在模型保存之前发送的信号。大多数时候,你不需要知道 任何 模型何时被保存——只需要知道某个 特定 模型何时被保存。

    在这些情况下,您可以注册以接收仅由特定发送者发送的信号。在接收 信号时 ,发送器会是要保存的模型类,因此你就可以表明你想要某个模型发送的信号:

    my_handler 函数将仅在 MyModel 实例保存后被调用。

    不同的信号使用不同的对象作为它们的发送者;你需要查阅 内置信号文档 了解每个特定信号的详细信息。

    防止重复信号

    在某些情况下,连接接收器到信号的代码可能被执行多次。这可能会导致接收器函数被注册多次,因此对于一个信号事件调用同样多次。例如,ready() 方法在测试期间可能被多次执行。更普遍的是,在项目的任何地方导入定义信号的模块都会发生这种情况,因为信号注册的运行次数与导入的次数相同。

    如果此行为会产生问题(例如在保存模型时使用信号发送电子邮件),则传递一个唯一标识符作为 dispatch_uid 参数来标识接收方函数。这个标识符通常是一个字符串,尽管任何可散列对象都可以。最终的结果是,对于每个唯一的 dispatch_uid 值,接收器函数只与信号绑定一次:

    1. from django.core.signals import request_finished
    2. request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

    您的应用程序可以利用信号基础设施并提供自己的信号。

    信号是隐式函数调用,这使得调试更加困难。如果你的自定义信号的发送器和接收器都在你的项目内,最好使用显式函数调用。

    class Signal

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

    例如:

    这声明了一个 pizza_done 信号。

    发送信号

    在 Django 中有两种发送信号的方法。

    Signal.send(sender, \*kwargs*)[源代码]

    Signal.send_robust(sender, \*kwargs*)

    要发送信号,调用 Signal.send() (所有内置信号使用这个)或者 。你必须提供 sender 参数(大多数情况下是一个类),还可以根据需要提供任意多个其他关键字参数。

    例如,发送 pizza_done 信号可能看起来如下:

    1. class PizzaStore:
    2. ...
    3. ...

    send()send_robust() 都返回一个元组对列表 [(receiver, response), ... ],表示被调用的接收器函数及其响应值的列表。

    send()send_robust() 在处理接收器函数所引发异常的方式上有所不同。 send() 捕获接收器引起的任何异常;它只是允许错误传播。因此,并非所有的接收器都会在出现错误时被通知信号。

    send_robust() 捕获从 Python的 Exception 类派生的所有错误,并确保所有接收器都收到信号通知。如果发生错误,将在引发错误的接收器的元组对中返回错误实例。

    回溯出现在调用 send_robust() 时返回的错误中的 __traceback__ 属性中。

    Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)[源代码]

    To disconnect a receiver from a signal, call . The arguments are as described in Signal.connect(). The method returns True if a receiver was disconnected and False if not. When sender is passed as a lazy reference to <app label>.<model>, this method always returns None.

    receiver 参数表明要断开的接收器。它可以是 None 如果 已经被用来标识接收器。