Django - 覆盖保存方法时检查旧值和新值之间的差异

Posted

技术标签:

【中文标题】Django - 覆盖保存方法时检查旧值和新值之间的差异【英文标题】:Django - Check diference between old and new value when overriding save method 【发布时间】:2012-10-09 05:48:44 【问题描述】:

感谢您的宝贵时间。

我使用的是 Django 1.4,并且我有以下代码:它是我的 Quest 模型的覆盖保存方法。

@commit_on_success
def save(self, *args, **kwargs):
    from ib.quest.models.quest_status_update import QuestStatusUpdate
    created = not self.pk

    if not created:
        quest = Quest.objects.get(pk=self)
        # CHECK FOR SOME OLD VALUE
    super(Quest, self).save(*args, **kwargs)

我找不到这样做的聪明方法。对我当前正在更新的对象进行新查询以找出旧的实例值对我来说似乎很愚蠢。

有没有更好的方法来做到这一点?

谢谢大家。

弗朗西斯科

【问题讨论】:

更新和保存的上下文是什么? IE。直接在模型上的视图中或通过 ModelForm 等? 嗯,这真的相关吗?我正在保存方法,更新实例。但无论如何,这个电话是从一个视图中发出的,我在那里打电话给quest.save() 我不确定是否有干净的方法可以做到这一点。您可以将旧对象传递给 save() 方法或在 save() 中查询它。 是的,它是相关的。如果您使用的是模型表单,它会将实例(旧值)和新值存储在其自身中。所以如果你覆盖它的 save() 你可以得到字段值和 self.instance 字段值。直接在模型上进行 - 我使用下面建议的信号。我将使用 django-reversion 举一个例子。 嗯...这非常好!感谢您的洞察力。我去查一下! 【参考方案1】:

您可以将旧值存储在 init 方法中:

def __init__(self, *args, **kwargs):
    super(MyModel, self).__init__(*args, **kwargs)
    self.old_my_field = self.my_field

def save(self, *args, **kwargs):
    print self.old_my_field
    print self.my_field

您可能可以使用 deepcopy 或类似的东西来复制整个对象,以供以后在保存和删除方法中使用。

【讨论】:

超级简单易读。加上它完美地工作。很好的解决方案。【参考方案2】:

Django 不会缓存模型实例的旧值,因此您需要自己执行此操作或在保存之前执行另一个查询。

一种常见的模式是使用预保存信号(或将此代码直接放入您的 save() 方法中,就像您所做的那样):

old_instance = MyModel.objects.get(pk=instance.pk)
# compare instance with old_instance, and maybe decide whether to continue

如果您想保留旧值的缓存,那么您可能会在视图代码中这样做:

from copy import deepcopy
object = MyModel.objects.get(pk=some_value)
cache = deepcopy(object)

# Do something with object, and then compare with cache before saving

在 django-developers 上也有 a recent discussion 关于这个问题,还有一些其他可能的解决方案。

【讨论】:

感谢您的解决方案。这可行,但如果您使用 save_as,则 pk 设置为 None。有什么解决方法吗?【参考方案3】:

我正在使用 django-reversion 信号检查与旧值的差异,但相同的逻辑将适用于保存信号。对我而言,不同之处在于我想保存该字段是否已保存。

@receiver(reversion.pre_revision_commit)
def it_worked(sender, **kwargs):
    currentVersion = kwargs.pop('versions')[0].field_dict
    fieldList = currentVersion.keys()
    fieldList.remove('id')
    commentDict = 
    print fieldList
    try:
        pastVersion = reversion.get_for_object(kwargs.pop('instances')[0])[0].field_dict
    except IndexError:
        for field in fieldList:
            commentDict[field] = "Created"
        comment = commentDict
    except TypeError:
        for field in fieldList:
            commentDict[field] = "Deleted"
        comment = commentDict
    else:
        for field in fieldList:
            try:
                pastTest = pastVersion[field]
            except KeyError:
                commentDict[field] = "Created"
            else:       
                if currentVersion[field] != pastTest:
                    commentDict[field] = "Changed"
                else:
                    commentDict[field] = "Unchanged"
        comment = commentDict
    revision = kwargs.pop('revision')
    revision.comment = comment
    revision.save()
    kwargs['revision'] = revision
    sender.save_revision

【讨论】:

以上是关于Django - 覆盖保存方法时检查旧值和新值之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

将 SaveChange 中的旧值和新值保存为 DbEntityEntry.Entity 以进行审计

Symfony2 表单验证器 - 在刷新之前比较旧值和新值

Ext.net 行编辑旧值和新值

如何在 C# 中 PropertyChanged 事件的 INotifyPropertyChanged 实现中捕获旧值和新值

如何在 SQL Server 的触发器中获取多个字段的旧值和新值?

如何在ios的同一个Nsmutablearray中存储旧值和新值