所以我使用 django-simple-history 模块来跟踪模型实例的变化。但是,它使用 post_save 信号来执行此操作。在我的项目中,我还需要它在 update() 上触发。
我的问题是:如何覆盖 update() 方法来触发 post_save 信号?
这样做的问题是,
.update()
不需要从数据库加载对象来完成它的任务。考虑一下具有 100 万行的 users 表的示例:
users = User.objects.filter(date_joined__lte=now() - timedelta(days=30)
users.update(is_active=False)
django 在这里要做的不是从数据库中加载潜在的数十万行,只是将
is_active
设置为 False,然后单独保存每一行,而是直接通过数据库引擎发出 UPDATE
命令: UPDATE users SET is_active=False WHERE date_joined < 30_DAYS_AGO
。这是 Django 在更新时不触发 post_save
的唯一原因:因为它一开始就没有从数据库加载任何内容。
为了触发信号,它需要从数据库加载所有这些对象,发出数据库查询
UPDATE users SET is_active=False WHERE id=X
数千次,每行一次,然后发送信号。这会降低性能。
如果您确实想使用该信号,则需要从数据库加载对象,迭代它们并一次保存一个。不幸的是,没有办法解决这个问题。
我们可以重写方法并手动调用 post_save :
class CustomQuerySet(models.QuerySet):
def update(self, **kwargs):
# Get instances before the update (this will fetch objects from DB)
instance_list = list(self)
# Perform the update operation
updated_count = super().update(**kwargs)
# Send post_save signal manually for each instance
for instance in instance_list:
for key, value in kwargs.items():
setattr(instance, key, value)
post_save.send(sender=self.model, instance=instance, created=False)
return updated_count
def bulk_create(self, objs, **kwargs):
# Send pre_save signal for each instance
for obj in objs:
pre_save.send(sender=self.model, instance=obj)
# Perform bulk_create
created_objs = super().bulk_create(objs, **kwargs)
# Send post_save signal for each created instance
for obj in created_objs:
post_save.send(sender=self.model, instance=obj, created=True)
return created_objs
def bulk_update(self, objs, fields, **kwargs):
# Send pre_save signal for each instance
for obj in objs:
pre_save.send(sender=self.model, instance=obj)
# Perform bulk_update
result = super().bulk_update(objs, fields, **kwargs)
# Send post_save signal for each instance
for obj in objs:
post_save.send(sender=self.model, instance=obj, created=False)
return result
class SignalManager(models.Manager):
def get_queryset(self):
return CustomQuerySet(self.model, using=self._db)
然后在模型中使用 SignalManger 如下:
class MyModel(models.Model):
objects = SignalManager()
save() 方法在 Django 模型对象创建或更新时被调用。
例如: 创建新的用户配置文件, 更新现有的用户个人资料。
对于这两种场景,我们可以使用Django信号发送邮件来通知用户。
为此,我们使用 Django 内置信号 post_save。
只要在 Django 模型实例上调用 .save() ,就会调度 post_signal 。
我们可以在 models.py 中使用以下代码:
from django.db.models import signals
from django.dispatch import receiver
@receiver(signals.post_save, sender=Customer)
def on_create_or_updated_obj(sender, instance, **kwargs):
if kwargs['created']:
print 'obj created'
#send user created email to user
else:
print 'obj updated'
#logic for sending user updated email to user