Python中Django的信号机制是什么原理?

from django.dispatch import Signal

user_logged_in = Signal(providing_args=[“request”, “user”])

Typically followed by user_logged_in (unless, e-mail verification kicks in)

user_signed_up = Signal(providing_args=[“request”, “user”])

怎么样才能触发这两个信号?


Python中Django的信号机制是什么原理?

7 回复

四个小时前是鬼


Django的信号机制本质上是一个观察者模式(或发布-订阅模式)的实现。核心原理是通过Signal类维护一个接收器(receiver)列表,当发送者(sender)触发信号时,自动同步调用所有已连接的接收器函数。

关键组件和工作流程如下:

  1. Signal类:每个信号都是django.dispatch.Signal的实例。它内部维护一个receivers列表,存储着接收器函数及其标识。

  2. 接收器连接:使用信号的connect()方法将接收器函数注册到该信号。Django内置信号(如post_save)在模型操作时由框架自动发送。

  3. 信号发送:调用信号的send()send_robust()方法触发信号。发送时遍历receivers列表,以同步方式调用每个接收器。

  4. 接收器调用:每个接收器函数接收sender**kwargs参数,执行自定义逻辑。

这里是一个完整的最小化示例,展示自定义信号的创建、连接和触发:

# signals_demo.py
from django.dispatch import Signal, receiver

# 1. 创建自定义信号
order_completed = Signal()

# 2. 定义接收器函数
@receiver(order_completed)
def handle_order_completion(sender, **kwargs):
    order_id = kwargs.get('order_id')
    print(f"[接收器1] 订单 {order_id} 处理完成,来自 {sender}")

def another_handler(sender, **kwargs):
    order_id = kwargs.get('order_id')
    print(f"[接收器2] 记录订单 {order_id} 日志")

# 3. 连接接收器(装饰器自动连接,也可手动连接)
order_completed.connect(another_handler)

# 4. 发送信号
class Order:
    pass

order = Order()
order_completed.send(sender=Order, order_id=12345)

运行上述代码将输出:

[接收器1] 订单 12345 处理完成,来自 <class '__main__.Order'>
[接收器2] 记录订单 12345 日志

内部原理细节

  • Signal类使用弱引用存储接收器,避免内存泄漏。
  • send()方法返回一个元组列表,包含每个接收器的调用结果。
  • send_robust()会捕获异常并继续执行其他接收器。
  • 内置信号由Django在特定动作(如pre_savepost_save)时自动发送。

一句话总结:信号本质是一个同步的回调函数管理器,通过维护接收器列表并在事件发生时遍历调用它们来实现解耦。

user_logged_in.send(sender=xx,request=xx,user=xx)
user_signed_up.send(sender=xx,request=xx,user=xx)
上面这两句就是触发这两个信号了,不过你还要先定义接收函数,如

(user_logged_in)
def 某函数

大概理解了
sender 我写 self 没事吧?

原理的话很简单,signal 里面有个 receivers 属性,是个 list, 有函数被 receiver 装饰了,就把这个函数 append 到 signal 的 receivers 属性里。然后调用这个 signal.send 函数的时候,就依次调用 receivers 里面的函数

我用的 arango-orm 库由于没有事件机制,我就自己写了,你可以看下相当简单的,还有单元测试。
https://github.com/wonderbeyond/arango-orm/commit/1559cba970ea28fe96536efb739f8d558ef7370d

其实就是定义了一个 signal: handler 的映射, 你发送信号时, 会去搜索对应的回调函数然后调用
看看 django/dispatch/dispatcher.py 文件中的 Signal.send 函数, receiver就是信号接收函数,也就是 receiver 修饰器修饰的函数。 感觉这段代码,平平无奇啊~ 没有黑科技的感觉

python<br>def send(self, sender, **named):<br> responses = []<br> if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:<br> return responses<br><br> for receiver in self._live_receivers(sender):<br> response = receiver(signal=self, sender=sender, **named)<br> responses.append((receiver, response))<br> return responses<br><br>

回到顶部