【问题标题】:Keeping track of changes since the last save in django models跟踪自上次保存 django 模型以来的更改
【发布时间】:2010-01-08 18:37:49
【问题描述】:

有几次我遇到过这样的情况,在节省时间时我需要知道哪些模型字段将被更新并采取相应的行动。

对此最明显的解决方案是获取主键字段并从数据库中检索模型的副本:

class MyModel(models.Model):

    def save(self, force_insert=False, force_update=False, using=None):
        if self.id is not None:
            unsaved_copy = MyModel.objects.get(id=self.id)
            # Do your comparisons here
        super(MyModel, self).save(force_insert, force_update, using)

这工作得很好,但是,它会针对您正在保存的模型的每个实例访问数据库(如果您要进行大量此类保存,可能会很不方便)。

很明显,如果可以“记住”模型实例生命周期开始时的旧字段值(__init__),则不需要从数据库中检索模型的副本。所以我想出了这个小技巧:

class MyModel(models.Model):

    def __init__(self, *args, **kwargs):
        super(MyModel, self).__init__(*args, **kwargs)
        self.unsaved = {}
        for field in self._meta.fields:
            self.unsaved[field.name] = getattr(self, field.name, None)

    def save(self, force_insert=False, force_update=False, using=None):
        for name, value in self.unsaved.iteritems():
            print "Field:%s Old:%s New:%s" % (name, value, getattr(self, name, None))
        # old values can be accessed through the self.unsaved member
        super(MyModel, self).save(force_insert, force_update, using)

这似乎可行,但它使用了django.db.models.Model 的非公共接口。

也许有人知道一种更清洁的方法?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    我认为您的解决方案看起来很合理。

    或者,您可以使用一个名为 get_and_copy()(或其他名称)的 Manager 方法,将原始对象的副本从返回的对象中挂起。然后,您可以使用另一个 Manager 方法,save_and_check(),它利用了复制的原件。

    FWIW:如果您正在使用 contrib/admin 模板,则会有一个名为 original 的上下文变量,它是原始对象的副本。

    更新:我更仔细地查看了管理员在做什么。在class ModelAdmin(位于django/contrib/admin/options.py)中有一个方法叫做construct_change_message()。它由formset.changed_dataformset.changed_objects 驱动,所以 django/forms/models.py class BaseModelFormSet 是行动所在。参见方法save_existing_objects()。另请查看方法_existing_object()。它比我之前提到的要复杂一些,因为它们要处理多个对象的可能性,但它们基本上是在第一次访问时缓存查询集的结果。

    【讨论】:

    • 不,我不是在管理模板的上下文中询问它,但是我会在那里检查它是如何完成的,谢谢你的提示。
    【解决方案2】:

    这不适用于固定装置。 loaddata 命令使用 models.Model.base_save。可能最简洁的方法是对字段使用描述符,但必须弄清楚如何正确插入它们。

    【讨论】:

      猜你喜欢
      • 2017-07-14
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      相关资源
      最近更新 更多