A couple of times I've run into a situation, when at save time I need to know which model fields are going to be updated and act accordingly.
The most obvious solution to this is to take the primary key field and retrieve a copy of the model from the database:
class MyModel(models.Model):
def save(self, force_insert=False, force_update=False, using=None):
if self.id is not None:
unsaved_copy = MyModel.objects.get(id=self.id)
# Do your comparisons here
super(MyModel, self).save(force_insert, force_update, using)
That works perfectly fine, however, it hits the database for every instance of the model you are saving (might be quite inconvenient if you are doing a lot of such saves).
It is obvious, that if one can "remember" the old field values at the start of model instance's lifetime (__init__
), there should be no need to retrieve a copy of the model from the database. So I came up with this little hack:
class MyModel(models.Model):
def __init__(self, *args, **kwargs):
super(MyModel, self).__init__(*args, **kwargs)
self.unsaved = {}
for field in self._meta.fields:
self.unsaved[field.name] = getattr(self, field.name, None)
def save(self, force_insert=False, force_update=False, using=None):
for name, value in self.unsaved.iteritems():
print "Field:%s Old:%s New:%s" % (name, value, getattr(self, name, None))
# old values can be accessed through the self.unsaved member
super(MyModel, self).save(force_insert, force_update, using)
This seems to work, however it makes use of the non-public interface of django.db.models.Model
.
Perhaps someone knows a cleaner way to do it?