Skip to content

Commit 8c62d09

Browse files
committed
fix(history): make history aware of potential proxy models
1 parent c40c22b commit 8c62d09

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

caluma/caluma_core/models.py

+56-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import uuid_extensions
2+
from django.apps import apps
23
from django.db import models
3-
from simple_history.models import HistoricalRecords
4+
from simple_history.models import HistoricalRecords, registered_models
45

56

67
def _history_user_getter(historical_instance):
@@ -17,8 +18,61 @@ def _history_user_setter(historical_instance, user):
1718
historical_instance.history_user_id = user
1819

1920

21+
class ProxyAwareHistoricalRecords(HistoricalRecords):
22+
"""Historical records with shared history for proxy models.
23+
24+
This is a workaround for https://github.com/jazzband/django-simple-history/issues/544.
25+
26+
Copied from https://github.com/jazzband/django-simple-history/issues/544#issuecomment-1538615799
27+
"""
28+
29+
def _find_base_history(self, opts):
30+
base_history = None
31+
for parent_class in opts.parents.keys():
32+
if hasattr(parent_class, "history"):
33+
base_history = parent_class.history.model
34+
return base_history
35+
36+
def create_history_model(self, model, inherited):
37+
opts = model._meta
38+
if opts.proxy:
39+
base_history = self._find_base_history(opts)
40+
if base_history:
41+
return self.create_proxy_history_model(model, inherited, base_history)
42+
43+
return super().create_history_model(model, inherited)
44+
45+
def create_proxy_history_model(self, model, inherited, base_history):
46+
opts = model._meta
47+
attrs = {
48+
"__module__": self.module,
49+
"_history_excluded_fields": self.excluded_fields,
50+
}
51+
app_module = f"{opts.app_label}.models"
52+
if inherited:
53+
attrs["__module__"] = model.__module__
54+
elif model.__module__ != self.module: # pragma: no cover
55+
# registered under different app
56+
attrs["__module__"] = self.module
57+
elif app_module != self.module: # pragma: no cover
58+
# Abuse an internal API because the app registry is loading.
59+
app = apps.app_configs[opts.app_label]
60+
models_module = app.name
61+
attrs["__module__"] = models_module
62+
63+
attrs.update(
64+
Meta=type("Meta", (), {**self.get_meta_options(model), "proxy": True})
65+
)
66+
if self.table_name is not None: # pragma: no cover
67+
attrs["Meta"].db_table = self.table_name
68+
69+
name = self.get_history_model_name(model)
70+
registered_models[opts.db_table] = model
71+
return type(str(name), (base_history,), attrs)
72+
73+
2074
class HistoricalModel(models.Model):
21-
history = HistoricalRecords(
75+
history = ProxyAwareHistoricalRecords(
2276
inherit=True,
2377
history_user_id_field=models.CharField(null=True, max_length=150),
2478
history_user_setter=_history_user_setter,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from caluma.caluma_workflow.models import WorkItem
2+
3+
4+
def test_proxy_model_history(db, work_item):
5+
class ProxyWorkItem(WorkItem):
6+
class Meta:
7+
proxy = True
8+
9+
proxy_work_item = ProxyWorkItem.objects.get(pk=work_item.pk)
10+
11+
assert work_item.history.count() == 1
12+
assert proxy_work_item.history.count() == 1
13+
14+
proxy_work_item.name = "Foo"
15+
proxy_work_item.save()
16+
17+
assert work_item.history.count() == 2
18+
assert proxy_work_item.history.count() == 2

0 commit comments

Comments
 (0)