Skip to content

Commit 02eed4f

Browse files
Fixed #36648, Refs #33772 -- Accounted for composite pks in first()/last() when aggregating.
1 parent cc9df52 commit 02eed4f

3 files changed

Lines changed: 32 additions & 2 deletions

File tree

django/db/models/query.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,8 +2141,14 @@ def _check_operator_queryset(self, other, operator_):
21412141
raise TypeError(f"Cannot use {operator_} operator with combined queryset.")
21422142

21432143
def _check_ordering_first_last_queryset_aggregation(self, method):
2144-
if isinstance(self.query.group_by, tuple) and not any(
2145-
col.output_field is self.model._meta.pk for col in self.query.group_by
2144+
if (
2145+
isinstance(self.query.group_by, tuple)
2146+
# Raise if the pk fields are not in the group_by.
2147+
and self.model._meta.pk
2148+
not in {col.output_field for col in self.query.group_by}
2149+
and set(self.model._meta.pk_fields).difference(
2150+
{col.target for col in self.query.group_by}
2151+
)
21462152
):
21472153
raise TypeError(
21482154
f"Cannot use QuerySet.{method}() on an unordered queryset performing "

docs/releases/5.2.8.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ Bugfixes
1010
========
1111

1212
* Added compatibility for ``oracledb`` 3.4.0 (:ticket:`36646`).
13+
14+
* Fixed a bug in Django 5.2 where ``QuerySet.first()`` and ``QuerySet.last()``
15+
raised an error on querysets performing aggregation that selected all fields
16+
of a composite primary key.

tests/composite_pk/test_aggregate.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,23 @@ def test_max_pk(self):
141141
msg = "Max expression does not support composite primary keys."
142142
with self.assertRaisesMessage(ValueError, msg):
143143
Comment.objects.aggregate(Max("pk"))
144+
145+
def test_first_from_unordered_queryset_aggregation_pk_selected(self):
146+
self.assertEqual(
147+
Comment.objects.values("pk").annotate(max=Max("id")).first(),
148+
{"pk": (1, 1), "max": 1},
149+
)
150+
151+
def test_first_from_unordered_queryset_aggregation_pk_selected_separately(self):
152+
self.assertEqual(
153+
Comment.objects.values("tenant", "id").annotate(max=Max("id")).first(),
154+
{"tenant": 1, "id": 1, "max": 1},
155+
)
156+
157+
def test_first_from_unordered_queryset_aggregation_pk_incomplete(self):
158+
msg = (
159+
"Cannot use QuerySet.first() on an unordered queryset performing "
160+
"aggregation. Add an ordering with order_by()."
161+
)
162+
with self.assertRaisesMessage(TypeError, msg):
163+
Comment.objects.values("tenant").annotate(max=Max("id")).first()

0 commit comments

Comments
 (0)