「保存一次,信号触发两次」是 Django 里常见的坑。这篇不去猜,直接复现能让它发生的几种情形,再用 dispatch_uid 解决。
同一个 h 连接两次,save 一次触发: 1 再连接两个「工厂造出来的相同代码」的函数,共 3 个 receiver 里有效的: 3 次触发(1 个 h + 2 个新函数)
第一次(lab.handlers)导入后 receiver 数: 1 用另一个名字(handlers_again)再导入同一个文件后 receiver 数: 2 保存一次:lab.handlers.COUNT = 1 handlers_again.COUNT = 1
实验里用 spec_from_file_location 加载同一个文件、模块名不同来模拟。至于真实项目里是哪种导入路径不一致造成的,本文没有复现,只模拟了「同一文件、两个模块名」。
同一段代码执行 3 次(模拟重复导入),dispatch_uid 相同 → 保存一次触发: 1
在「ready()」里 connect 一个 lambda,连续执行 3 次 → receiver 增加了 3 个(每个 lambda 都是新对象)
只要 connect 的调用会执行多次(测试里的 setUp、被重复调用的 ready()),传入的又是每次都新建的函数,receiver 就会累加。