【问题标题】:Can I make a django model object immutable?我可以使 django 模型对象不可变吗?
【发布时间】:2011-03-08 18:22:26
【问题描述】:

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

但我想知道是否存在使对象不可变的通用模式,因此我不会在稍后的某个地方意外调用 save 并搞砸数据库中的数据。而且“不可变”在这里可能不是正确的词,它更像是解除对象与模型的关联,因此数据永远无法返回数据库。

我的第一个想法是重写 save 方法什么都不做,这样就够了吗?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

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

    迄今为止我想出的最好的,如果有点简单的解决方案如下所示:

    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)
    

    通过这种方式,用户会被告知他们正在执行的操作不受支持,而不仅仅是静默失败。

    【讨论】:

    • 这对我来说似乎是最合理的。有什么方法可以绕过save() 而这不起作用?
    • 我不这么认为。来自文档:“要将对象保存回数据库,请调用 save()”和“如果您想要自定义保存行为,您可以覆盖此 save() 方法。有关更多详细信息,请参阅覆盖预定义模型方法。”最后是“覆盖内置方法的经典用例是,如果您希望在保存对象时发生某些事情。例如(有关它接受的参数的文档,请参见 save())”
    • 仅供参考,这不应被视为 100% 保存,因为您仍然可以使用 queryset.update() 更改对象(它绕过 save() 方法)。
    【解决方案2】:

    如果你想让你的 instance 不可变,这里最简单的做法是编写一个小包装器:

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

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

    blog = Blog.objects.get(name='Django')
    blog.save()  # writes to the database
    freeze_instance(blog)
    blog.save()  # NotImplementedError
    

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

    【讨论】:

      【解决方案3】:

      以这种方式覆盖普通模型的save() 方法可能会很麻烦,因此您应该考虑将proxy modelsave() 方法一起使用,如果调用该方法会引发异常。

      【讨论】:

      • 当我只是在一个实例上覆盖它时怎么会很麻烦?我想它只是更改了该实例的“保存”属性,而不是模型本身,对吧?
      • 好吧,无论如何更改实例而不是类的方法很麻烦。
      • 我喜欢在调用时抛出异常的想法,这样你就知道你的代码可能会在哪里出错!
      【解决方案4】:

      还有一些库,例如 django-immutablemodeldjango-immutablefield,它们为不可变模型提供了更全面的 api。

      【讨论】:

      • 仅供参考,这两个模块都被 Py3 / 现代 Django 版本破坏了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-15
      • 1970-01-01
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多