我可以使django模型对象不可变吗?

gui*_*ism 8 django django-models

我的代码中有些地方我想临时更改模型对象的某些属性而不更改数据库中的数据.显然Django和Python使这很容易做到,我只需要设置属性而不调用save.

但我想知道是否有一个使对象不可变的常见模式,所以我不小心在后面的某个地方调用save并搞砸了我的数据库中的数据.也许"不可变"在这里不是正确的词,它更像是将对象与模型解除关联,因此数据无法返回数据库.

我的第一个想法是只是覆盖保存方法什么都不做,这就够了吗?

pno*_*nak 6

我知道这个问题已经很老了,但是仍然非常重要。

迄今为止,我提出的最好的解决方案似乎是这样。

class ModelName(models.Model):
    # fields, etc...
    def save(self, *args, **kwargs):
        if self.pk:
            raise ValidationError("you may not edit an existing %s" % self._meta.model_name)
        super(ModelName, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这样,用户将被告知他们所执行的操作不受支持,而不仅仅是默默地失败。

  • 仅供参考,这不应被视为 100% 保存,因为您仍然可以使用 `queryset.update()` 更改对象(它绕过 `save()` 方法)。 (6认同)

小智 5

如果你想让你的实例不可变,在这里最简单的事情就是编写一个小包装器:

def _model_save_base(*args, **kwargs):
    raise NotImplementedError("Cannot save a frozen instance.")

def freeze_instance(obj):
    obj.save_base = _model_save_base
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的对象上调用 freeze_instance:

blog = Blog.objects.get(name='Django')
blog.save()  # writes to the database
freeze_instance(blog)
blog.save()  # NotImplementedError
Run Code Online (Sandbox Code Playgroud)

您始终可以通过创建自定义异常来改进这一点。或者您可以将 freeze_instance 添加到您的博客模型中。但这主要是风格。


Ign*_*ams 4

save()以这种方式重写普通模型的方法可能会很麻烦,因此您应该考虑使用代理模型,其save()方法在调用时会抛出异常。