使用内建信号
Django 提供了一系列内建信号,比如 pre_save
、post_save
、request_started
、setting_changed
等等。
例如:想在车辆(Car)保存之后打印一条信息。
- 创建 cars/signals.py :
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Car
@receiver(post_save, sender=Car)
def onCarPostSave(sender, **kwargs):
car = kwargs['instance']
print(car.__str__)
- 修改 cars/apps.py :
from django.apps import AppConfig
class CarsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'cars'
def ready(self):
# Implicitly connect a signal handlers decorated with @receiver.
from . import signals
自定义信号
举例:在添加车辆失败时,将请求参数打印出来。
- 修改 cars/signals.py :
...
from django.dispatch import Signal
...
def onSaveCarError(sender, **kwargs):
request = kwargs['request']
print(request.body)
create_car_failed = Signal() # 定义信号
create_car_failed.connect(onSaveCarError) # 连接 Callback 函数
- 修改 cars/views.py :
...
from .signals import create_car_failed
...
class MyCars(View):
...
def post(self, request):
'''
添加车辆
'''
...
if form.is_valid():
...
else:
create_car_failed.send(sender=self.__class__, request=request) # 发送信号
return JsonResponse({'error': form.errors})
...
防止重复信号
在某些情况下,连接接收器到信号的代码可能被执行多次。这可能会导致接收器函数被注册多次,因此对于一个信号事件调用同样多次。例如,ready() 方法在测试期间可能被多次执行。更普遍的是,在项目的任何地方导入定义信号的模块都会发生这种情况,因为信号注册的运行次数与导入的次数相同。
如果此行为会产生问题(例如在保存模型时使用信号发送电子邮件),则传递一个唯一标识符作为dispatch_uid
参数来标识接收方函数。这个标识符通常是一个字符串,尽管任何可散列对象都可以。最终的结果是,对于每个唯一的dispatch_uid
值,接收器函数只与信号绑定一次:
from django.core.signals import request_finished
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")