Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check previous model value on save

I have a model that saves an Excursion. The user can change this excursion, but I need to know what the excursion was before he change it, because I keep track of how many "bookings" are made per excursion, and if you change your excursion, I need to remove one booking from the previous excursion.

Im not entirely sure how this should be done.

Im guessing you use a signal for this?

Should I use pre_save, pre_init or what would be the best for this?

pre_save is not the correct one it seems, as it prints the new values, not the "old value" as I expected

@receiver(pre_save, sender=Delegate)
def my_callback(sender, instance, *args, **kwargs):
    print instance.excursion
like image 858
Harry Avatar asked Sep 03 '14 14:09

Harry


3 Answers

Do you have several options.

First one is to overwrite save method:

#Delegate
def save(self, *args, **kwargs):
    if self.pk:
        previous_excursion = Delegate.objects.get(self.pk).excursion
    super(Model, self).save(*args, **kwargs)
    if self.pk and self.excursion != previous_excursion:
        #change booking

Second one is binding function to post save signal + django model utils field tracker:

@receiver(post_save, sender=Delegate)
def create_change_booking(sender,instance, signal, created, **kwargs):
    if created:
        previous_excursion = get it from django model utils field tracker
        #change booking

And another solution is in pre_save as you are running:

@receiver(pre_save, sender=Delegate)
def my_callback(sender, instance, *args, **kwargs):
    previous_excursion = Delegate.objects.get(self.pk).excursion
    if instance.pk and instance.excursion != previous_excursion:
        #change booking  
like image 153
dani herrera Avatar answered Nov 09 '22 17:11

dani herrera


You can use django model utils to track django model fields. check this example.

pip install django-model-utils

Then you can define your model and use fieldtracker in your model .

from django.db import models
from model_utils import FieldTracker

class Post(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    tracker = FieldTracker()
    status = models.CharField(choices=STATUS, default=STATUS.draft, max_length=20)

after that in post save you can use like this :

@receiver(post_save, sender=Post) 
def my_callback(sender, instance,*args, **kwargs):
    print (instance.title)
    print (instance.tracker.previous('title'))
    print (instance.status)
    print (instance.tracker.previous('status'))

This will help you a lot to do activity on status change. as because overwrite save method is not good idea.

like image 33
Yogesh dwivedi Geitpl Avatar answered Nov 09 '22 17:11

Yogesh dwivedi Geitpl


As an alternative and if you are using Django forms:

The to-be version of your instance is stored in form.instance of the Django form of your model. On save, validations are run and this new version is applied to the model and then the model is saved.

Meaning that you can check differences between the new and the old version by comparing form.instance to the current model.

This is what happens when the Django Admin's save_model method is called. (See contrib/admin/options.py)

If you can make use of Django forms, this is the most Djangothic way to go, I'd say.

This is the essence on using the Django form for handling data changes:

form = ModelForm(request.POST, request.FILES, instance=obj)
new_object = form.instance  # not saved yet
# changes are stored in form.changed_data
new_saved_object = form.save()

form.changed_data will contain the changed fields which means that it is empty if there are no changes.

like image 1
Risadinha Avatar answered Nov 09 '22 17:11

Risadinha