from django.db import models from simple_history.models import HistoricalRecords from django.contrib.contenttypes.fields import GenericRelation from django.utils.timezone import now class CustomHistoricalRecords(HistoricalRecords): """Custom historical records that properly handle generic relations.""" def copy_fields(self, model): """ Copy fields from the model to the historical record model, excluding GenericRelation fields. """ fields = {} for field in model._meta.concrete_fields: if not isinstance(field, GenericRelation) and field.name not in [ 'comments', 'comment_threads', 'photos', 'reviews' ]: fields[field.name] = field.clone() return fields def create_history_model(self, model, inherited): """ Override to ensure we don't create duplicate auto fields. """ attrs = { '__module__': model.__module__, '_history_excluded_fields': ['comments', 'comment_threads', 'photos', 'reviews'], } app_module = '%s.models' % model._meta.app_label if inherited: # inherited use models.AutoField instead of models.IntegerField attrs.update({ 'id': models.AutoField(primary_key=True), 'history_id': models.AutoField(primary_key=True), 'history_date': models.DateTimeField(default=now), 'history_change_reason': models.CharField(max_length=100, null=True), 'history_type': models.CharField(max_length=1, choices=( ('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted'), )), 'history_user': models.ForeignKey( 'accounts.User', null=True, on_delete=models.SET_NULL, related_name='+' ), }) # Convert field to point to historical model fields = self.copy_fields(model) attrs.update(fields) return type( str('Historical%s' % model._meta.object_name), (models.Model,), attrs )