Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Check diference between old and new value when overriding save method

thanks for your time.

I'm on Django 1.4, and I have the following code: Its the overriden save method for my Quest model.

@commit_on_success
def save(self, *args, **kwargs):
    from ib.quest.models.quest_status_update import QuestStatusUpdate
    created = not self.pk

    if not created:
        quest = Quest.objects.get(pk=self)
        # CHECK FOR SOME OLD VALUE
    super(Quest, self).save(*args, **kwargs)

I couldn't find out a smart way of doing this. It seems very silly to me to have to make a new query for the object i'm currently updating in order to find out an old instance value.

Is there a better way to do this?

Thank you all.

Francisco

like image 783
Francisco Avatar asked Oct 18 '12 17:10

Francisco


People also ask

When saving How can you check if a field has changed Django?

To check if a field has changed when saving with Python Django, we can override the `init method of the model class to keep a copt of the original value. to add the __init__ method that sets the __original_name variable to self.name to keep the original name value.

What does save() do in Django?

Creating objects To create an object, instantiate it using keyword arguments to the model class, then call save() to save it to the database. This performs an INSERT SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() . The save() method has no return value.

How do I override model save in Django?

Whenever one tries to create an instance of a model either from admin interface or django shell, save() function is run. We can override save function before storing the data in the database to apply some constraint or fill some ready only fields like SlugField.


2 Answers

You can store the old value inside the init method:

def __init__(self, *args, **kwargs):
    super(MyModel, self).__init__(*args, **kwargs)
    self.old_my_field = self.my_field

def save(self, *args, **kwargs):
    print self.old_my_field
    print self.my_field

You can probably use deepcopy or something alike to copy the whole object for later use in the save and delete methods.

like image 106
Simon Steinberger Avatar answered Sep 28 '22 20:09

Simon Steinberger


Django doesn't cache the old values of the model instance, so you need to do that yourself or perform another query before save.

One common pattern is to use a pre-save signal (or put this code directly in your save() method, as you've done):

old_instance = MyModel.objects.get(pk=instance.pk)
# compare instance with old_instance, and maybe decide whether to continue

If you want to keep a cache of the old values, then you would probably do that in your view code:

from copy import deepcopy
object = MyModel.objects.get(pk=some_value)
cache = deepcopy(object)

# Do something with object, and then compare with cache before saving

There was a recent discussion on django-developers about this as well, with some other possible solutions.

like image 27
Ian Clelland Avatar answered Sep 28 '22 20:09

Ian Clelland