I'm working on a Django project for which I'll need to store the historic information of many models.
So far, I'm using the following strategy:
- Memoize the relevant values in
__init__
. - When saving, check if a relevant value has changed.
- If a relevant value has changed, save memoized values into a "history" model.
My code goes as follows:
from django.db import models
from core.models import User
class Spam(models.Model):
user= models.OneToOneField(User, on_delete=models.PROTECT, related_name='spam')
ham = models.CharField(max_length=10)
eggs = models.IntegerField()
def __init__(self, *args, **kwargs):
super(Spam, self).__init__(*args, **kwargs)
self.__relevant_fields = ['ham', 'eggs']
self._memoize()
def _memoize(self):
for f in self.__relevant_fields:
setattr(self, '__prev_%s' % f, getattr(self, f))
def _get_prev_value(self, f):
return getattr(self, '__prev_%s' % f)
def _dirty_field(self, f) -> bool:
return getattr(self, '__prev_%s' % f) != getattr(self, f)
def _dirty(self) -> bool:
return any([self._dirty_field(f) for f in self.__relevant_fields])
def _save_history(self):
history = dict()
for f in self.__relevant_fields:
history[f] = self._get_prev_value(f)
self.user.spam_history.create(**history)
def save(self, *args, **kwargs):
super(Spam, self).save(*args, **kwargs)
if self._dirty():
self._save_history()
class SpamHistory(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='spam_history')
ham = models.CharField(max_length=10)
eggs = models.IntegerField()
Although this approach works, there are some things that make me uncomfortable:
- I need to do this for many models, so I'm repeating myself a lot! I'm looking into inheritance, mixins or the like, but so far I haven't found a right way to make it work.
- Is this the best approach to achieve what I want? Considering that I will need to fetch historic records frequently, I need the "history" model for each model I need to keep history from.
So, my specific questions are:
- Am I implementing a good strategy for keeping the history of my model(s)?
- Is there a way to improve this strategy by using an inheritance or mixin strategy?