Skip to content

Instantly share code, notes, and snippets.

@cb109
Forked from dcramer/track_data.py
Last active July 25, 2022 08:08
Show Gist options
  • Save cb109/e6e3aedb2f7ddc94eb9a9805168f3f57 to your computer and use it in GitHub Desktop.
Save cb109/e6e3aedb2f7ddc94eb9a9805168f3f57 to your computer and use it in GitHub Desktop.
Tracking changes on properties in Django
# Tested against Django 3.2.14.
from django.db.models.base import DEFERRED
def track_data(*fields):
"""Tracks property changes on a model instance.
Simplified version of David Cramer's gist:
https://gist.github.com/dcramer/730765
Please note that this decorator is not meant to be used in mixins
or generally in any form of class hierarchy. You should also only
track fields that exist on the class this is added to.
"""
def inner(cls):
def _store_current_field_values(self):
self.__data = {}
for field in fields:
try:
self.__data[field] = getattr(self, field)
except KeyError:
continue
cls._store_current_field_values = _store_current_field_values
def has_changed(self, field):
return self.__data[field] != getattr(self, field)
cls.has_changed = has_changed
def old_value(self, field):
return self.__data.get(field)
cls.old_value = old_value
def new_init(self, *args, **kwargs):
# If we get deferred fields in here, trying to track their
# values it will send us into infinite recursion as the
# model instance is reinitialized for each field being
# queried from the database. This happens e.g. when deleting
# a model instance, where tracking is irrelevant, so skip it
# in that case.
has_deferred_fields = DEFERRED in args
new_init._original_init(self, *args, **kwargs)
if not has_deferred_fields:
self._store_current_field_values()
new_init._original_init = cls.__init__
cls.__init__ = new_init
def new_save(self, *args, **kwargs):
new_save._original_save(self, *args, **kwargs)
self._store_current_field_values()
new_save._original_save = cls.save
cls.save = new_save
return cls
return inner
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment