5

Model definitions:

class Footprint(models.Model)
  date = models.DateTimeField(auto_now = True)

class Stuff(Footprint):
  name = models.CharField(max_length = 255)
  some_other_field = models.CharField(max_length = 255)

In a Stuff object, I'd like to only update the name field, and leave all the other fields unchanged, except those defined in the associated Footprint object.

Fields in the Footprint object are correctly updated if I don't use update_fields:

s = Stuff.objects.get(pk = 1)
s.name = 'Alexander'
s.save()

s.date # is correctly set

But if I specify fields to update, the associated Footprint is not not even saved.

s = Stuff.objects.get(pk = 1)
s.name = 'Tim'
s.save(update_fields = ['name'])

s.date # unfortunately, remains unchanged!!

I have to use update_fields to avoid interferences between several scripts.

At the same time, I'd like to always keep track of the last modification, defined by the "Footprint" object (it contains the last modification date, as well as several other fields; their update is triggered by a custom save() method).

Is there a way to force a call to Footprint.save() even if update_fields doesn't contain any field from Footprint?

alexpirine
  • 3,023
  • 1
  • 26
  • 41

3 Answers3

10

Instead of rewriting the save() method, the other possibility is to add all the fields with the auto_now option to the update parameter. Like this:

some_object.save(update_fields = ['updated_field', 'auto_now_date']
alexpirine
  • 3,023
  • 1
  • 26
  • 41
  • Guys really good solution here if you want one time change instead of overriding all the save method! – Or Duan Sep 01 '16 at 15:26
2

It was enough to simply rewrite the Footprint model definition like this:

class Footprint(models.Model)
  date = models.DateTimeField(auto_now = True)

  def save(self, *args, **kwargs):
    if kwargs.has_key('update_fields'):
      kwargs['update_fields'] = list(set(list(kwargs['update_fields']) + ['date']))

    return super(Footprint, self).save(*args, **kwargs)

Of course, if you have more fields to update than just a date field, you just have to append them in the list.

alexpirine
  • 3,023
  • 1
  • 26
  • 41
0

You can do this by changing your .save() method. Now, I now sure what it is that you want to do exactly, so I will leave you a template, since I believe wanting to have your own way of saving changes is indeed what do yo want.

In your class add this function definition:

def save(self, *args, **kwargs):
    # Do something here, whatever it is that you want
    return super(<YourClassName>, self).save(self, *args, **kwargs)

This keep the features of the normal save() function unchanged and add your custom changes to the changes you want to make as well.

Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
  • Thank you, it actually may be a way to do what I requested. I could add `p.footprint_ptr.save()` in the save method before calling `super()`, only if an `update_fields` argument exists. Since many models inherit from `Footprint`, is there a way to avoid redundant code? (only `` will be different each time) – alexpirine Jul 04 '13 at 17:30
  • Well, you could turn save into a classmethod, but I don't have the kind of Python experience to help you if anything goes wrong. Try solving your problem via this, and give me an update if you were able to manage. Make sure you call save at the very end. So, if you want to change the `name` field for example, its something like `self.name = #whatever#`, then you go save, and the method signature for save is the same in all cases. – Games Brainiac Jul 04 '13 at 18:05
  • After further investigation, it appears that the `save` method of the Footprint object was already called (which is not so strange, because there is standard Python inheritance). So there is no need for `super(…).save(…)`. – alexpirine Jul 09 '13 at 05:45