8

Is it possible to detect that field in Django model has been changed?

class Product(models.Model): my_current_price = MoneyField(max_digits=20, decimal_places=2, null=True, blank=True, verbose_name=_('My original price')) my_eur_price = MoneyField(max_digits=20, decimal_places=2, null=True, blank=True, verbose_name=_('My price in EUR')) my_usd_price = MoneyField(max_digits=20, decimal_places=2, null=True, blank=True, verbose_name=_('My price in USD')) 

The thing is that I need to recalculate EUR and USD price anytime when my_current_price is changed.

I have two ideas:

  1. Somehow override MoneyField and send signal when the field is changed.

  2. Override save method and create a new attribute __my_current_price like here - this works but it makes code very unclear for me.

EDIT: I store the price in different currencies because of faster database lookups.

6
  • yes use signal for post_save, when current_price will be changed according to it, the other 2 fields will be calculated and saved Commented Jul 5, 2017 at 7:43
  • How can I then detect that current_price is changed? Commented Jul 5, 2017 at 7:44
  • @Exprator Oh yes, you mean this answer? stackoverflow.com/a/7934958/3371056 It seems good. Commented Jul 5, 2017 at 7:46
  • yes thats what signal i was talking about :) Commented Jul 5, 2017 at 7:48
  • Although this is a good way, I'm thinking about using pre_save - is it possible? With pre_save, there would be just one commit. I'm not sure if I can access objects not commited changes in pre save. Commented Jul 5, 2017 at 7:59

1 Answer 1

15

One way is to create a signal and compare instance with an object from database. But it seems that better way is to override save method which is a best practice.

def save(self,*args,**kwargs): old = Model.objects.filter(pk=getattr(self,pk,None)).first() if old: if old.attr!=self.attr: # attr changed super(Model,self).save(*args,**kwargs) 
Sign up to request clarification or add additional context in comments.

1 Comment

QuerySets are lazy, using them as a boolean value will execute a corresponding query in the database. Instead remove the .first() and check the existence of the instance by doing old.exists()

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.