Skip to content

Commit

Permalink
Ensure pghistory.track supports concrete inheritance (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
wesleykendall authored Sep 11, 2024
1 parent 27d8d4a commit 8a70865
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 3.4.2 (2024-09-10)

#### Fixes

- Fix using `@pghistory.track()` on models that have concrete inheritance by [@wesleykendall](https://github.com/wesleykendall) in [#164](https://github.com/Opus10/django-pghistory/pull/164).

## 3.4.1 (2024-09-06)

#### Fixes
Expand Down
2 changes: 1 addition & 1 deletion pghistory/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from pghistory.core import Tracker


def default_trackers() -> Union[Tuple["Tracker"], None]:
def default_trackers() -> Union[Tuple["Tracker", ...], None]:
"""
The default event trackers.
Expand Down
7 changes: 3 additions & 4 deletions pghistory/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ class MyEventModel(create_event_model(
# Add custom indices or change default field declarations...
""" # noqa
if not trackers:
trackers = config.default_trackers() or [InsertEvent(), UpdateEvent()]
trackers = config.default_trackers() or (InsertEvent(), UpdateEvent())

event_model = import_string("pghistory.models.Event")
base_model = base_model or config.base_model()
Expand All @@ -436,10 +436,9 @@ class MyEventModel(create_event_model(
attrs.update({"pgh_trackers": trackers})
meta = meta or {}
exclude = exclude or []
all_fields = (tracked_model._meta.concrete_model or tracked_model)._meta.local_fields
fields = (
fields
if fields is not None
else [f.name for f in tracked_model._meta.fields if f.name not in exclude]
fields if fields is not None else [f.name for f in all_fields if f.name not in exclude]
)

if append_only:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Generated by Django 4.2.6 on 2024-09-11 00:46

import django.db.models.deletion
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("pghistory", "0006_delete_aggregateevent"),
("tests", "0012_alter_bigautofieldmodelevent_pgh_context_and_more"),
]

operations = [
migrations.CreateModel(
name="ConcreteParent",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=32)),
],
),
migrations.CreateModel(
name="ConcreteChild",
fields=[
(
"concreteparent_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="tests.concreteparent",
),
),
("age", models.IntegerField()),
],
bases=("tests.concreteparent",),
),
migrations.CreateModel(
name="ConcreteChildEvent",
fields=[
(
"concreteparent_ptr",
models.ForeignKey(
auto_created=True,
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
parent_link=True,
related_name="+",
related_query_name="+",
serialize=False,
to="tests.concreteparent",
),
),
("pgh_id", models.AutoField(primary_key=True, serialize=False)),
("pgh_created_at", models.DateTimeField(auto_now_add=True)),
("pgh_label", models.TextField(help_text="The event label.")),
("age", models.IntegerField()),
(
"pgh_context",
models.ForeignKey(
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="+",
to="pghistory.context",
),
),
(
"pgh_obj",
models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name="events",
to="tests.concretechild",
),
),
],
options={
"abstract": False,
},
),
pgtrigger.migrations.AddTrigger(
model_name="concretechild",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "tests_concretechildevent" ("age", "concreteparent_ptr_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id") VALUES (NEW."age", NEW."concreteparent_ptr_id", _pgh_attach_context(), NOW(), \'insert\', NEW."concreteparent_ptr_id"); RETURN NULL;', # noqa: E501
hash="5740a1af0415e809c3fec2214084f412670d95f9",
operation="INSERT",
pgid="pgtrigger_insert_insert_a6cf2",
table="tests_concretechild",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="concretechild",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition='WHEN (OLD."age" IS DISTINCT FROM (NEW."age") OR OLD."concreteparent_ptr_id" IS DISTINCT FROM (NEW."concreteparent_ptr_id"))', # noqa: E501
func='INSERT INTO "tests_concretechildevent" ("age", "concreteparent_ptr_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id") VALUES (NEW."age", NEW."concreteparent_ptr_id", _pgh_attach_context(), NOW(), \'update\', NEW."concreteparent_ptr_id"); RETURN NULL;', # noqa: E501
hash="3bbc47abd3ad6a8677edfd77204000b426c45357",
operation="UPDATE",
pgid="pgtrigger_update_update_1163f",
table="tests_concretechild",
when="AFTER",
),
),
),
]
9 changes: 9 additions & 0 deletions pghistory/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,12 @@ class IgnoreAutoFieldsSnapshotModel(models.Model):
my_char_field = models.CharField(max_length=32)
my_int_field = models.IntegerField()
untracked_field = models.CharField(max_length=32)


class ConcreteParent(models.Model):
name = models.CharField(max_length=32)


@pghistory.track()
class ConcreteChild(ConcreteParent):
age = models.IntegerField()
9 changes: 9 additions & 0 deletions pghistory/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,3 +787,12 @@ def test_conditional_untracked_field():
m.my_int_field = 1
m.save()
assert snapshot_model.objects.count() == 1


@pytest.mark.django_db
def test_concrete_inheritance():
"""
Verifies that triggers work with concrete inheritance
"""
m = ddf.G(test_models.ConcreteChild, name="John", age=20)
assert m.events.all().count() == 1
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ packages = [
exclude = [
"*/tests/"
]
version = "3.4.1"
version = "3.4.2"
description = "History tracking for Django and Postgres"
authors = ["Wes Kendall"]
classifiers = [
Expand Down

0 comments on commit 8a70865

Please sign in to comment.