我正在使用django的post_save信号在保存模型后执行一些语句。
class Mode(models.Model):
name = models.CharField(max_length=5)
mode = models.BooleanField()
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Mode)
def post_save(sender, instance, created, **kwargs):
# do some stuff
pass
现在我想基于mode
字段的值是否已更改来执行语句。
@receiver(post_save, sender=Mode)
def post_save(sender, instance, created, **kwargs):
# if value of `mode` has changed:
# then do this
# else:
# do that
pass
我查看了一些SOF主题和博客,但找不到解决方案。所有这些都试图使用不是我的用例的pre_save方法或表单。 django docs中的https://docs.djangoproject.com/es/1.9/ref/signals/#post-save没有提到直接的方法来做到这一点。
下面的链接中的答案看起来很有希望,但我不知道如何使用它。我不确定最新的django版本是否支持它,因为我使用ipdb
来调试它,并发现instance
变量没有属性has_changed
,如下面的答案所述。
Django: When saving, how can you check if a field has changed?
将其设置在您模型的__init__
上,以便您可以访问它。
def __init__(self, *args, **kwargs):
super(YourModel, self).__init__(*args, **kwargs)
self.__original_mode = self.mode
现在你可以执行以下操作:
if instance.mode != instance.__original_mode:
# do something useful
通常,覆盖保存方法比使用信号更好。
来自Two scoops of django:“使用信号作为最后的手段。”
我同意@scoopseven关于在init上缓存原始值的答案,但是如果可能则覆盖save方法。
class Mode(models.Model):
name = models.CharField(max_length=5)
mode = models.BooleanField()
__original_mode = None
def __init__(self, *args, **kwargs):
super(Mode, self).__init__(*args, **kwargs)
self.__original_mode = self.mode
def save(self, force_insert=False, force_update=False, *args, **kwargs):
if self.mode != self.__original_mode:
# then do this
else:
# do that
super(Mode, self).save(force_insert, force_update, *args, **kwargs)
self.__original_mode = self.mode
这是一个老问题,但我最近遇到过这种情况,我通过以下方式完成了它:
class Mode(models.Model):
def save(self, *args, **kwargs):
if self.pk:
# If self.pk is not None then it's an update.
cls = self.__class__
old = cls.objects.get(pk=self.pk)
# This will get the current model state since super().save() isn't called yet.
new = self # This gets the newly instantiated Mode object with the new values.
changed_fields = []
for field in cls._meta.get_fields():
field_name = field.name
try:
if getattr(old, field_name) != getattr(new, field_name):
changed_fields.append(field_name)
except Exception as ex: # Catch field does not exist exception
pass
kwargs['update_fields'] = changed_fields
super().save(*args, **kwargs)
这更有效,因为它捕获了应用程序和django-admin的所有更新/保存。
如果要比较保存操作之前和之后的状态,可以使用pre_save
信号为数据库更新后提供实例,在pre_save中,您可以读取数据库中实例的当前状态并根据差异执行某些操作。
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
@receiver(pre_save, sender=MyModel)
def on_cahnge(sender, instance: MyModel, **kwargs):
if instance.id is None: # new object will be created
pass # write your code hier
else:
previous = MyModel.objects.get(id=instance.id)
if previous.field_a != instance.field_a: # fielad will be updated
pass # write your code hier