jayt
jayt

Reputation: 768

Django - Pass value from pre_save to post_save methods on model

I've got a Django model like so...

class Example(models.Model):
    title = models.CharField(...)
    ...

I'm trying to compare two values - the title field before the user changes it, and the title after. I don't want to save both values in the database at one time (only need one title field), so I'd like to use pre_save and post_save methods to do this. Is it possible to get the title before the save, then hold this value to be passed into the post_save method?

The pre_save and post_save methods look like so...

@receiver(pre_save, sender=Example, uid='...')
def compare_title_changes(sender, instance, **kwargs):
    # get the current title name here
    x = instance.title

@receiver(post_save, sender=Example, uid='...')
def compare_title_changes(sender, instance, **kwargs):
    # get the new title name here and compare the difference
    x = instance.title # <- new title
    if x == old_title_name: # <- this is currently undefined, but should be retrieved from the pre_save method somehow
        ...do some logic here...

Any ideas would be greatly appreciated!

Edit

As was pointed out to me, pre_save and post_save both occur after save() is called. What I was looking for is something like pre_save() but before the actual save method is called. I set this on the model so that the logic to be performed will be accessible wherever the instance is saved from (either admin or from a user view)

Upvotes: 1

Views: 3834

Answers (2)

Sachin G.
Sachin G.

Reputation: 1980

We can only say object has changed if "save" method passes successfully, so post_save is good to be sure that model object has updated.

Setting on the fly attribute on model class instance can do the task, as the same instance is passed from pre_save to post_save.

def set_flag_on_pre_save(sender, instance, *args, **kwargs):
    # Check here if flag setting condition satisfies
    set_the_flag = true
    if set_the_flag:  
      instance.my_flag=0


def check_flag_on_post_save(sender, instance, *args, **kwargs):
   try:
      print(instance.my_flag)
      print('Flag set') 
   except AttributeError:
      print('Flag not set')


pre_save.connect(set_flag_on_pre_save, sender=ModelClass)

post_save.connect(check_flag_on_post_save, sender=ModelClass)

Upvotes: 1

gdlmx
gdlmx

Reputation: 6789

Use Example.objects.get(pk=instance.id) to get the old title from the database in the pre_save handler function:

@receiver(pre_save, sender=Example, uid='...')
def compare_title_changes(sender, instance, **kwargs):

    new_title = instance.title  # this is the updated value
    old_title = Example.objects.get(pk=instance.id)
    # Compare the old and new titles here ...

This trick was proposed here a long time ago. I've not tested it with the recent Django version. Please let me know whether it's still working.

Upvotes: 5

Related Questions