django-simple-history
django-simple-history copied to clipboard
Django polymorphic compatibility
Hello everyone,
First of all, let me thank you for this awesome package. It was a real pleasure to use it to track changes in my models.
Problem Statement
I have tried using it with a pair of models that use django-polymorphic and couldn't manage to make it work how I wanted.
Here's a minimal reproducible example of my models:
from polymorphic.models import PolymorphicModel
class BaseStage(PolymorphicModel):
name = models.CharField(max_length=256)
display_name = models.CharField(null=True, max_length=256)
history = HistoricalRecords(inherit=True)
class Company(BaseStage):
basestage_ptr = models.OneToOneField(
BaseStage,
parent_link=True,
related_name="company_ptr",
on_delete=models.RESTRICT,
)
class Stage(BaseStage):
parent = HistoricForeignKey(BaseStage, on_delete=models.RESTRICT, related_name="children")
company = models.ForeignKey("Company", on_delete=models.RESTRICT, default=1, related_name="stages")
The goal was to store the hierarchy of a company in a tree. Our requirements were the following:
- Root of the tree can only be a company instance
- Nodes are all linked to their parent and to the company
Describe the solution you'd like
I would have loved to be able to do:
BaseStage.history.filter(Q(Company___pk=company.id) | Q(Stage___company=company))
Just like in django polymorphic.
This would avoid doing something like this:
qs = Stage.history.filter(
id__in=BaseStage.objects.filter(Q(Company___pk=pk) | Q(Stage___company=pk)).values_list("id", flat=True),
)
dates = qs.values_list("history_date", flat=True)
dates.extend(Company.history.filter(pk=pk).values_list("history_date", flat=True)
When one could do:
BaseStage.history.filter(Q(Company___pk=company.id) | Q(Stage___company=company)).values_list("history_date", flat=True)
In order to obtain all the history dates of the whole tree.
Describe alternatives you've considered
I have tried to use Polymorphic as base but couldn't manage to make it work:
class PolymorphicHistoricalRecords(HistoricalRecords):
def __init__(self, *args, bases=(PolymorphicModel,), **kwargs):
return super().__init__(*args, bases=bases, **kwargs)
class BaseStage(PolymorphicModel):
history = PolymorphicHistoricalRecords(inherit=True)
It seems that the HistoricXX classes never inherit from PolymorphicModel
.
Additional context
I am pretty sure that this would need changes about field naming in either this module or in django polymorphic because django polymorphic needs a polymorphic_ctype
column, creating a history on a polymorphic model also generates it and having a polymorphic history on a polymorphic model would require this column twice.