我有这样的代码:
# ...
obj = Model.objects.get(pk=2342)
if foo:
obj.foo = 'bar'
if bar:
obj.bar = 'baz'
obj.save()
是否有一种很好的方法可以确定是否修改了模型实例,以防止每次代码运行时都保存它?
答案 0 :(得分:4)
典型的模式是做类似的事情:
model = Model.objects.get(pk=2342)
dirty = False
if foo:
model.foo = 'bar'
dirty = True
if bar:
model.bar = 'baz'
dirty = True
if dirty:
model.save()
答案 1 :(得分:1)
只需逐个字段地展示当前模型实例的'snapshot'实例,就可以获得snapshot
到copy.copy(obj)
或model_cls.objects.get(pk=obj.pk)
。
您也可以简单地比较转储版本:
from django.core.serializers.json import Serializer
dump = Serializer.serialize([obj])
...
changed = dump == Serializer.serialize([obj])
通常情况下,调整代码最简单:
obj = Model.objects.get(pk=2342) # 'obj' is better than 'model', IMO
changed = False
if foo:
...
obj.foo = 'bar'
changed = True
if bar:
...
obj.bar = 'baz'
changed = True
if changed:
obj.save()
答案 2 :(得分:0)
Django在内部执行此检查。除非模型实际发生了变化,否则不会触发SQL查询。
<强>更新强>
这个答案是对的。我的错。我把这与别的东西混淆了。
答案 3 :(得分:0)
要以更抽象的方式执行此操作,请查看模型方法from_db()
的文档,该模型方法是将数据从数据库加载到模型实例中时调用的钩子。使用此方法,您可以在加载字段时缓存其原始值,然后将其与save()
方法中的当前值进行比较。
示例(注意,我尚未实际测试此代码):
class SaveIfModified(models.Model):
foo = models.TextField()
@classmethod
def from_db(cls, db, field_names, values):
instance = super().from_db(db, field_names, values)
# caveat: deferred values won't appear here
if "foo" in field_names:
instance._foo = values[field_names.index("foo")]
return instance
def save(self, *args, **kwargs):
if self.foo == getattr(self, "_foo", None):
return
super().save(*args, **kwargs)