# history_tracking/models.py from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey from simple_history.models import HistoricalRecords from .mixins import HistoricalChangeMixin from typing import Any, Type, TypeVar, cast from django.db.models import QuerySet T = TypeVar('T', bound=models.Model) class HistoricalModel(models.Model): """Abstract base class for models with history tracking""" id = models.BigAutoField(primary_key=True) history: HistoricalRecords = HistoricalRecords( inherit=True, bases=(HistoricalChangeMixin,) ) class Meta: abstract = True @property def _history_model(self) -> Type[T]: """Get the history model class""" return cast(Type[T], self.history.model) # type: ignore def get_history(self) -> QuerySet: """Get all history records for this instance""" model = self._history_model return model.objects.filter(id=self.pk).order_by('-history_date') class HistoricalSlug(models.Model): """Track historical slugs for models""" content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') slug = models.SlugField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('content_type', 'slug') indexes = [ models.Index(fields=['content_type', 'object_id']), models.Index(fields=['slug']), ] def __str__(self) -> str: return f"{self.content_type} - {self.object_id} - {self.slug}"