什么是signal

所谓signal其实就是发送信号触发某类操作,比如model对象save时就会触发pre-save、post-save,注册了这两个signal的函数就会被调用。简单来说,可以理解成一种general的observer模式实现。

signal是怎么运行的

要知道signal的运行机制就先来看看django默认提供的那些,

  • pre-save、post-save、pre-delete、post-delete

在代码中调用model.save()/model.delete()操作时就会触发上述部分signal,去翻看其源代码就会发现,

signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using)
...
signals.post_save.send(sender=origin, instance=self, created=(not record_exists), raw=raw, using=using)

很容易就可以看到signal的触发是主动发送的,在model的save函数中会主动发送pre-save、post-save两个signal,delete操作的代码也可想而知了。

signal可以用在什么地方

signal并不是什么特别的东西,因此可以用在任何地方。但是signal机制把隔离了代码逻辑,某种程度上说降低了代码的可读性,滥用signal可能会导致代码支离破碎。

  • 避免自定义signal

从signal的运行机制可以看出signal是需要主动触发的,因此对于自己实现的代码来说在触发signal的地方直接调用对应的逻辑函数又有什么不可以呢?这样在阅读代码时直接就能够知道会触发哪些操作了。 且使用signal的话,在这种地方ide就难以进行代码跳转了。

  • signal适用于hook django默认操作逻辑

比如通过model的post-save就可以方便的实现model级别的cache。这种场景下使用signal可以有效的降低代码复杂度。

使用signal需要注意的地方

signal用得不多,截至目前发现的有,

  • 避免signal重复触发

通过定义dispatch_uid来避免同一个注册了signal的函数被多次调用

  • 确保注册signal的函数被import,且注意避免循环import问题

比如在command里面调用了model save操作,但如果注册了post-save signal的函数代码所在的py module没有在当前command运行过程中被import话,那么你认为那些会触发的操作其实不会被触发。