I recently had a software requirement in which I needed to send a notification when a model attribute changed. I looked a few third party projects, but they either did not do what I need or were not maintained, so I decided to role my own. Here is the solution, I came up with, via a Mixin:

import datetime

class DirtyMixin(object):
@property
def is_dirty(self):
	dirty_fields = []
	is_dirty = False
	if self.pk:
		db_obj = self.__class__.objects.get(id=self.pk)
		for f in self._meta.local_fields:
			if(self.__getattribute__(f.name),datetime):	
				try:
					attribute = self.__getattribute__(f.name)
					if attribute != db_obj.__getattribute__(f.name):
						dirty_fields.append(f.name)
						is_dirty = True
				except TypeError:
					pass
								
	return is_dirty, dirty_fields

If you want to use this, you can added a django signal to fire on Model.pre_save and you would add some code like this:

@staticmethod
def pre_save(sender, **kwargs):	
	from apps.accounts.models import User 
		
	instance = kwargs.get('instance')
	created = kwargs.get('created')


	is_dirty, dirty_fields = instance.is_dirty
	if is_dirty:
		# blah blah blah
...

models.signals.pre_save.connect(YOURMODEL.pre_save, sender=YOURMODEL)

If any model field has changed, then is_dirty will return True and dirty_fields will contain the field names of the fields that were updated.