Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django - comparing old and new field value before saving

I have a django model, and I need to compare old and new values of field BEFORE saving.

I've tried the save() inheritance, and pre_save signal. It was triggered correctly, but I can't find the list of actually changed fields and can't compare old and new values. Is there a way? I need it for optimization of pre-save actions.

Thank you!

like image 613
Y.N Avatar asked Apr 29 '14 09:04

Y.N


People also ask

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

Since Django 1.8 released, you can use from_db classmethod to cache old value of remote_image. Then in save method you can compare old and new value of field to check if the value has changed. @classmethod def from_db(cls, db, field_names, values): new = super(Alias, cls).

What is super save Django?

When you overwrite a function (of a class) you can call the function of the parent class using super . The save function in the models records the instance in the database. The first super(Review, self). save() is to obtain an id since it is generated automatically when an instance is saved in the database.

How do I save changes in Django model?

save() method can be used to insert new record and update existing record and generally used for saving instance of single record(row in mysql) in database. update() is not used to insert records and can be used to update multiple records(rows in mysql) in database.

How use Django save method?

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

There is very simple django way for doing it.

"Memorise" the values in model init like this:

def __init__(self, *args, **kwargs):     super(MyClass, self).__init__(*args, **kwargs)     self.initial_parametername = self.parametername     ---     self.initial_parameternameX = self.parameternameX 

Real life example:

At class:

def __init__(self, *args, **kwargs):     super(MyClass, self).__init__(*args, **kwargs)     self.__important_fields = ['target_type', 'target_id', 'target_object', 'number', 'chain', 'expiration_date']     for field in self.__important_fields:         setattr(self, '__original_%s' % field, getattr(self, field))  def has_changed(self):     for field in self.__important_fields:         orig = '__original_%s' % field         if getattr(self, orig) != getattr(self, field):             return True     return False 

And then in modelform save method:

def save(self, force_insert=False, force_update=False, commit=True):     # Prep the data     obj = super(MyClassForm, self).save(commit=False)      if obj.has_changed():          # If we're down with commitment, save this shit         if commit:             obj.save(force_insert=True)      return obj 
like image 54
Odif Yltsaeb Avatar answered Sep 23 '22 10:09

Odif Yltsaeb


It is better to do this at ModelForm level.

There you get all the Data that you need for comparison in save method:

  1. self.data : Actual Data passed to the Form.
  2. self.cleaned_data : Data cleaned after validations, Contains Data eligible to be saved in the Model
  3. self.changed_data : List of Fields which have changed. This will be empty if nothing has changed

If you want to do this at Model level then you can follow the method specified in Odif's answer.

like image 34
Sahil kalra Avatar answered Sep 22 '22 10:09

Sahil kalra