Django Signal 代码布局
需要确保信号注册函数在使用前就被引入,所以理论上你可以将其置于满足上述条件的任意位置。
官方推荐
将信号处理器定义在关联 app 目录下的 signals.py
中,在关联 app 的 apps.AppConfig
下的 ready() 中使用注册函数或者引入带 @receiver
装饰器的处理器。
示例如下(strategy 是一个 app 名称):
strategy/signals.py
:
def create_orders(sender, **kwargs):
pass
@receiver(post_save)
def decorated_handler(sender, **kwargs):
pass
strategy/apps.py
:
from django.apps import AppConfig
from django.db.models.signals import post_save
from strategy.signals import create_orders
from strategy.models import Strategy
class StrategyConfig(AppConfig):
name = 'strategy'
def ready(self):
# 注册
post_save.connect(create_orders, sender=Strategy)
# 或者引入带 `@receiver` 装饰器的处理器
from strategy.signals import decorated_handler
通过 connect
注册更好。原因是 from strategy.signals import decorated_handler
会被 IDE 提示为引入而未使用。
注意
- 要在
ready()
内部而不能是外部引入其他的 model,否则会报错:django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
,原因是只有在ready()
中, 其他 model 才已经被定义好了 - INSTALLED_APPS 中的 app 应该指向对应的 AppConfig 路径,只有这样 Django 才会调用对应 app 的 AppConfig 否则只是调用 AppConfig 基类:
default_app_config allows applications that predate Django 1.7 such as django.contrib.admin to opt-in to AppConfig features without requiring users to update their INSTALLED_APPS.
New applications should avoid default_app_config. Instead they should require the dotted path to the appropriate AppConfig subclass to be configured explicitly in INSTALLED_APPS.[1]
放在 models.py
中
上面的放置方式与 models.py
的关联强度不够,所以这里将其放到 models.py
中。具体操作是:
- 将信号处理器以
classmethod
的方式定义在对应的 model 中- 在 models.py 的最下方统一注册[2]