'Can I make a django model object immutable?

There are places in my code where I want to temporarily change some of the attributes on a model object without changing the data in the database. Obviously Django and Python make this very easy to do, I just need to set the attribute without calling save.

But I'd like to know if there's a common pattern for making the object immutable so I don't accidentally call save somewhere later down the line and screw up the data in my database. And maybe "immutable" isn't the right word here, it's more like disassociating the object with the model so data can't ever get back to the database.

My first idea was to just override the save method to do nothing, would this be enough?



Solution 1:[1]

I know this question is pretty old, but is very much still relevant.

The best, if somewhat curt solution I've come up with to date looks like so:

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)

This way users are informed that the action they are performing is unsupported, rather than just silently failing.

Solution 2:[2]

The easiest thing to do here, if you are trying to make your instance immutable, is to write a little wrapper:

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

def freeze_instance(obj):
    obj.save_base = _model_save_base

Then you can call freeze_instance on your object:

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

You can always improve this by making a custom exception. Or you can add freeze_instance to your Blog model. But that's mostly stylistic.

Solution 3:[3]

Overriding the save() method of a normal model in such a manner can be troublesome, so you should consider using a proxy model with a save() method that throws an exception if called.

Solution 4:[4]

There are also a few libraries out there, like django-immutablemodel and django-immutablefield that provide a more comprehensive api for immutable models.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Simon Law
Solution 3 Ignacio Vazquez-Abrams
Solution 4 jstaab