如何确定Django modelform中的字段是否已更改

22

我很惊讶这件事很难做,但是我想出了这个方法,至少在我的简单情况下似乎有效。有人能推荐更好的方法吗?

def field_changed(self, fieldname):
    """Tests if the value of the field changed from the original data"""
    orig_value = self.fields[fieldname].initial or getattr(self.instance, field, None)
    orig_value = getattr(orig_value, 'pk', orig_value)
    if type(orig_value) is bool:
        # because None and False can be interchangeable
        return bool(self.data.get(fieldname)) != bool(orig_value)
    else:
        return unicode(self.data.get(fieldname)) != unicode(orig_value)
4个回答

53

表单包含一个属性 changed_data,其中保存了所有值已更改的字段的列表。

尝试:

'fieldname' in myforminstance.changed_data

8
技术说明:如果表单字段使用模型字段的默认值进行呈现,但该默认值尚未设置(例如在创建时),除非更改了默认值,否则该字段的名称将不会出现在changed_data列表中。 - trybik

19

如果有疑问,可以查阅文档;或者我也发现检查Django代码是找到所有可用方法的好方法。 - warath-coder
1
是的,Django源代码被很好地记录了下来,在某些方面相当富有教育意义。同时,良好的集成开发环境也非常有帮助,使得可以轻松访问到项目文件中的源代码。 - alTus
2
field.has_changed()作为负数似乎需要两个必需的位置参数:'initial'和'data'。这将需要检索原始表单数据和新表单数据,此时您可以自己比较新旧条目。Airs's answer更为简单明了。 - evantkchong

2

Airs的回答基础上进行扩展,适用于多个字段:

在需要跟踪变化的字段列表中['field_a', 'field_b', 'field_c']的场景下


如果您想检查是否有任何一个字段已更改:

any(x in myforminstance.changed_data for x in ['field_a', 'field_b', 'field_c'])

如果您想检查所有这些字段是否已更改:

如果您想检查所有这些字段是否已更改:

all(x in myforminstance.changed_data for x in ['field_a', 'field_b', 'field_c'])

-1

你必须重写方法post_save。在Django中,重写方法是一种良好的实践:https://docs.djangoproject.com/en/dev/ref/signals/#post-save

我建议你将类似以下代码添加到你的模型类中:

    def post_save(self, sender, instance, created, raw, using, update_fields):
        if 'the_field' in update_fields:
           # Do whatever...

信号的目的不是为了覆盖,而是为了监听信号。 - Matt
update_fields 不会列出已更改的字段,它只会列出传递给 save() 方法中的 update_fields。因此,某个字段可能会更改,但不包括在 update_fields 中。 - Tim Tisdall
你还能使用post_save中可用的任何参数来确保吗? - Rafa0809
post_save函数的签名应该包括**kwargs,这样(sender, update_fields, created, instance, **kwargs)将作为post_save参数工作。 - smrf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接