6

The problem

I have a field in my model that requires some calculation. I want to perform these calculations when the model is saved. However, because it is resource intensive, I want to only perform these calculations when certain fields have changed.

Initial thought

Keep the hash of the 3 fields as a different field in the model. On save, hash the three fields and, if equal to the the one currently saved in the model, continue on saving the instance without further work. Otherwise, perform calculations, save the results of the calculation and save new hash.

My questions:

  1. Is this the best option? If not, please share what would be better and why.

  2. If there isn't a better way: Which kind of hash should I use? And why?

  3. Which kind of Django model field type should I use to save the hash?

Belmin Fernandez
  • 8,307
  • 9
  • 51
  • 75
  • seems similar to this: http://stackoverflow.com/questions/4269605/django-overwrite-save-for-model/4269736#4269736 – crodjer Nov 29 '10 at 19:19
  • Thanks @dcrodjer. Answer http://stackoverflow.com/questions/4269605/django-overwrite-save-for-model/4269828#4269828 looks promising but I'm worried if it would cause me issues down the line. – Belmin Fernandez Nov 29 '10 at 21:31
  • Too bad Django hasn't implemented this patch yet: http://code.djangoproject.com/ticket/3148 – Belmin Fernandez Nov 29 '10 at 21:38

3 Answers3

4

I am submitting the implementation of my initial thought as an answer to be critiqued by others:

models.py

from hashlib import md5

class Stop(models.Model):
    line = models.CharField(max_length=12)
    street = models.CharField(max_length=32, choices=STREET_CHOICES)
    order = models.PositiveIntegerField(blank=True, null=True)
    location_hash = models.CharField(max_length=32, null=True)

    def save(self):
        location_hash = md5('%s@%s' % (self.line, self.street))
        if self.location_hash != location_hash:
            self.order = calculate_order(line=self.line, street=self.street)
            self.location_hash = location_hash
        super(Stop, self).save()

If anyone has any suggestions, comments or concerns; please share!

Belmin Fernandez
  • 8,307
  • 9
  • 51
  • 75
1

Supply request argument to the save method and define this custom save method:

def save(self, request=False, *args, **kwargs):
    if request and request.POST.get('var1',False) and request.POST.get('var2',False) and request.POST.get('var3',False):
        ######
        ##Do your calculations
        ######
    super(Model, self).save(*args, **kwargs)

Update your admin.py to something like this:

class ModelAdmin(admin.ModelAdmin):

    ....
    def save_model(self, request, obj, form, change): 
        instance = form.save(commit=False)
        instance.save(request=request)
        return instance
crodjer
  • 13,384
  • 9
  • 38
  • 52
0

Why not compare the instance with the db... something like:

class MyModel( models.Model ):
    description = models.CharField( max_length=12 )

    def save(self, *args, **kwargs):
        if not MyModel.objects.filter( id = self.id, description__exact = self.description ).exists():
            ### do complex logic here ###
        super( MyModel, self ).save( *args, **kwargs )
idbill
  • 362
  • 1
  • 7
  • I'm now using the ModelDiffMixin as shown in this other question: http://stackoverflow.com/questions/1355150/django-when-saving-how-can-you-check-if-a-field-has-changed/13842223#13842223 – idbill Nov 15 '13 at 18:51