Changes between Version 2 and Version 3 of Ticket #37473


Ignore:
Timestamp:
Nov 3, 2026, 4:52:38 PM (2 hours ago)
Author:
cheek-walnut
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #37473

    • Property Summary QuerySet.count() and aggregate() crash when values() selects only aggregate annotations → count() and aggregate() build an empty SELECT when values() selects only aggregate annotations
  • Ticket #37473 – Description

    v2 v3  
    1 When `values()` selects only an aggregate annotation, a following `aggregate()` over another field generates a subquery with an empty SELECT list.
     1When `values()` selects only an aggregate annotation, a following `count()`, or `aggregate()` over another field, generates a subquery with an empty SELECT list.
    22
    33{{{#!python
    … …  
    3131Expected `{'m': 40}`, as on Django 5.1, where the inner query selects `"app_author"."age" AS "__col1"`. `values_list("c")` fails the same way; `values("name", "c")` and `aggregate(m=Max("c"))` work.
    3232
    33 Regression in 65ad4ade74dc9208b9d686a451cd6045df0c9c3a (Refs #28900): the query works on its parent and fails on it. Reproduced on 5.2.19, 6.0.10, 6.1.3 and main with SQLite; 5.1.16 is not affected.
     33Regression in 65ad4ade74dc9208b9d686a451cd6045df0c9c3a (Refs #28900): the query works on its parent and fails on it. Reproduced on 5.2.19, 6.0.10, 6.1.3 and main with SQLite; 5.1.15 is not affected. On PostgreSQL (checked on 16), which accepts an empty SELECT list, `count()` returns the right number but `aggregate(m=Max("age"))` fails with `column "__col1" does not exist`.
    3434
    35 The cause appears to be `if self.selected:` in `Query.set_annotation_mask()` (django/db/models/sql/query.py:2568) and `Query.add_annotation()` (:1248), which treats an empty `selected` dict like `None`: after `get_aggregation()` masks the unused `c` annotation, `selected` is `{}` and the `__col1` column added for the aggregate is never added to it.
     35The cause appears to be `if self.selected:` in `Query.set_annotation_mask()` (django/db/models/sql/query.py:2568 at 5bd95c57a2) and `Query.add_annotation()` (:1248), which treats an empty `selected` dict like `None`: after `get_aggregation()` masks the unused `c` annotation, `selected` is `{}` and the `__col1` column added for the aggregate is never added to it. `count()` also goes through the fallback that selects the primary key when nothing else is selected (query.py:595-605), which only sets `inner_query.select` and is ignored once `selected` is `{}`, so changing the two checks to `is not None` fixes `aggregate()` but not `count()`.
    3636
    37 AI disclosure: found during a code audit with Claude Code 2.1.317 (Claude Opus 5.5), which also reduced the test case and ran it on the versions above and on 65ad4ade74 and its parent. I reviewed this report and re-ran the reproduction on main and 5.1.16.
     37AI disclosure: found during a code audit with Claude Code 2.1.317 (Claude Opus 5.5), which also reduced the test case and ran it on the versions above and on 65ad4ade74 and its parent. The PostgreSQL behavior and the `count()` note came from an independent review with ChatGPT Pro and were re-run with Claude Code. I reviewed this report and re-ran the reproduction on main and stable/5.1.x.
Back to Top