Skip to content

Django 5.2+ values() auto-aliasing breaks pghistory CTE references #202

Description

@mmirmoosavi

🔥 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions