17

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

5
  • what is the context of the update and save? ie. in a view directly on the model or via ModelForm etc. ? Commented Oct 18, 2012 at 17:29
  • Well, is this really relevant? I'm on save method, updating an instance. But anyway, this call is made from a view, and there I called quest.save() Commented Oct 18, 2012 at 17:31
  • I'm not sure there is clean way to do this. You may pass old object to save() method or query it in save() as you are doing it. Commented Oct 18, 2012 at 17:43
  • 2
    Yes it is relevant. If you were using a modelform it stores the instance (old values) and new values within its self. So if you override the its save() you could come the field value and self.instance field value. Doing it directly on the model - I use signals as suggested below. I will put an example using django-reversion. Commented Oct 18, 2012 at 18:24
  • hummmm... this is very nice! Thanks for the insight. I'll look it up! Commented Oct 19, 2012 at 15:05

3 Answers 3

21

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Super simple and easy to read. Plus it works perfectly. Excellent solution.
12

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.

1 Comment

thank you for the solution. This works but in case you use save_as the pk is set to None. Any workaround for this?
1

I am checking the difference to old values using a django-reversion signal, but the same logic would apply to the save signals. The difference for me being that I want to save whether the field was saved or not.

@receiver(reversion.pre_revision_commit) def it_worked(sender, **kwargs): currentVersion = kwargs.pop('versions')[0].field_dict fieldList = currentVersion.keys() fieldList.remove('id') commentDict = {} print fieldList try: pastVersion = reversion.get_for_object(kwargs.pop('instances')[0])[0].field_dict except IndexError: for field in fieldList: commentDict[field] = "Created" comment = commentDict except TypeError: for field in fieldList: commentDict[field] = "Deleted" comment = commentDict else: for field in fieldList: try: pastTest = pastVersion[field] except KeyError: commentDict[field] = "Created" else: if currentVersion[field] != pastTest: commentDict[field] = "Changed" else: commentDict[field] = "Unchanged" comment = commentDict revision = kwargs.pop('revision') revision.comment = comment revision.save() kwargs['revision'] = revision sender.save_revision 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.