Changes between Version 2 and Version 3 of Ticket #37473
- Timestamp:
- Nov 3, 2026, 4:52:38 PM (2 hours ago)
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 fieldgenerates a subquery with an empty SELECT list.1 When `values()` selects only an aggregate annotation, a following `count()`, or `aggregate()` over another field, generates a subquery with an empty SELECT list. 2 2 3 3 {{{#!python … … 31 31 Expected `{'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. 32 32 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.1 6 is not affected.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.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`. 34 34 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.35 The 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()`. 36 36 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.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. 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.