-
-
Save cb109/e6e3aedb2f7ddc94eb9a9805168f3f57 to your computer and use it in GitHub Desktop.
Tracking changes on properties in Django
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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