🔥 Problem
Starting with Django 5.2, all fields returned by QuerySet.values() are automatically aliased in the generated SQL—even when the alias is identical to the field name. This breaks pghistory's CTE-based logic, which relies on unaliased field names like pgh_obj_id.
✅ Works in Django 3.2
SELECT "branch_branchorderevent"."pgh_obj_id", ...
-- References remain unchanged
❌ Breaks in Django 5.2
SELECT "branch_branchorderevent"."pgh_obj_id" AS "pgh_obj", ...
-- Later reference to "pgh_obj_id" now fails
This results in SQL errors for downstream usage like:
WHERE "pgh_event_cte"."pgh_obj_id" = 194
-- ❌ Error: column pgh_event_cte.pgh_obj_id does not exist
🔍 Confirmed Setup
This issue occurs with a simple and valid @track usage like:
@track(
InsertEvent(),
UpdateEvent(),
DeleteEvent(),
append_only=False,
attrs=dict(
user=ProxyField(
"pgh_context__metadata__user",
models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING,
null=True,
help_text="The user associated with the event.",
),
)
),
)
class BranchOrder(BaseModel):
pass
🧪 Reproduced Error
Calling:
BranchOrder.objects.first().events.all()
Produces this SQL in Django 5.2:
WITH pgh_event_cte AS (
SELECT
branch_branchorderevent.pgh_id AS pgh_id,
branch_branchorderevent.pgh_label AS pgh_label,
branch_branchorderevent.pgh_obj_id AS pgh_obj,
...
FROM branch_branchorderevent
)
SELECT *
FROM pgh_event_cte
WHERE pgh_event_cte.pgh_obj_id = 123;
Which fails with:
ProgrammingError: column pgh_event_cte.pgh_obj_id does not exist
LINE 3: WHERE pgh_event_cte.pgh_obj_id = 123
🧠 Root Cause
Django 5.2+ automatically aliases fields selected via .values() or similar expressions. This includes:
Aliasing "pgh_obj_id" as "pgh_obj"
Breaking any downstream reference to the original name (e.g., pgh_obj_id)
This isn’t a bug in pghistory directly, but the library’s assumptions about field names no longer hold under Django’s new behavior.
✅ Expected Behavior
pghistory should ideally:
Detect Django version and adjust internal references accordingly, or
Use explicit aliases to retain field names like pgh_obj_id, pgh_context_id, etc., in CTEs, or
Make its query construction compatible with Django's new aliasing behavior.
🔥 Problem
Starting with Django 5.2, all fields returned by QuerySet.values() are automatically aliased in the generated SQL—even when the alias is identical to the field name. This breaks pghistory's CTE-based logic, which relies on unaliased field names like pgh_obj_id.
✅ Works in Django 3.2
SELECT "branch_branchorderevent"."pgh_obj_id", ...-- References remain unchanged
❌ Breaks in Django 5.2
SELECT "branch_branchorderevent"."pgh_obj_id" AS "pgh_obj", ...-- Later reference to "pgh_obj_id" now fails
This results in SQL errors for downstream usage like:
WHERE "pgh_event_cte"."pgh_obj_id" = 194-- ❌ Error: column pgh_event_cte.pgh_obj_id does not exist
🔍 Confirmed Setup
This issue occurs with a simple and valid @track usage like:
🧪 Reproduced Error
Calling:
BranchOrder.objects.first().events.all()Produces this SQL in Django 5.2:
Which fails with:
🧠 Root Cause
Django 5.2+ automatically aliases fields selected via .values() or similar expressions. This includes:
This isn’t a bug in pghistory directly, but the library’s assumptions about field names no longer hold under Django’s new behavior.
✅ Expected Behavior
pghistory should ideally: