Here's a little thing that can help you to improve the flexibility of your models.
Rather than trying to extend or override
Model.save(), if the special action you require only affects one field then define a subclass of the required Field type and define a
pre_save() method on the subclass. This will override the default method, which simply returns the attribute value.
I spotted this by following up a discussion of the planned removal of the DateField's
auto_now and
auto_now_add attributes, which you can assert to set a modification or creation date respectively on rows. Some developers suggested putting the functionality in a decorator that could be used on the model's
save() method, but Jacob Kaplan-Moss preferred a trivial subclass:
class AutoDateTimeField(models.DateTimeField):
def pre_save(self, model_instance, add):
return datetime.datetime.now()
Unfortunately this is just a little bit
too trivial, since
pre_save() is required to set the attribute value - every time for
auto_now and on first save for
auto_now_add. Fortunately the extra code required is pretty small.
pre_save() receives three arguments: the first is the field instance, the second is the model instance and the third is a flag which is
True only when the
save() call is adding a new row to the associated table.
class AutoNowDateTimeField(models.DateTimeField):
def pre_save(self, instance, add):
val = datetime.datetime.now()
setattr(instance, self.attname, val)
return val
class AutoNowAddDateTimeField(AutoNowDateTimeField):
def pre_save(self, instance, add):
if not add:
return getattr(instance, self.attname)
return AutoNowDateTimeField.pre_save(self, instance, add)
Technically it would be cleaner to use super() to access the superclass methods from AutoNowAddDateTimeField, but as a proof of concept this works fine.
As it happens the
auto_now and
auto_now_add attributes of DateTimeField were not removed before the release of Django 1.0, so we are likely to be stuck with them until 2.0. But the same technique is useful for any field that needs to receive an automatic value when a model instance is saved.