diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 103fffa47d..9865e88fd0 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1087,7 +1087,12 @@ class Query(BaseExpression): if select: self.append_annotation_mask([alias]) else: - self.set_annotation_mask(set(self.annotation_select).difference({alias})) + annotation_mask = ( + value + for value in dict.fromkeys(self.annotation_select) + if value != alias + ) + self.set_annotation_mask(annotation_mask) self.annotations[alias] = annotation def resolve_expression(self, query, *args, **kwargs): @@ -2341,12 +2346,12 @@ class Query(BaseExpression): if names is None: self.annotation_select_mask = None else: - self.annotation_select_mask = set(names) + self.annotation_select_mask = list(dict.fromkeys(names)) self._annotation_select_cache = None def append_annotation_mask(self, names): if self.annotation_select_mask is not None: - self.set_annotation_mask(self.annotation_select_mask.union(names)) + self.set_annotation_mask((*self.annotation_select_mask, *names)) def set_extra_mask(self, names): """ @@ -2423,9 +2428,9 @@ class Query(BaseExpression): return {} elif self.annotation_select_mask is not None: self._annotation_select_cache = { - k: v - for k, v in self.annotations.items() - if k in self.annotation_select_mask + k: self.annotations[k] + for k in self.annotation_select_mask + if k in self.annotations } return self._annotation_select_cache else: diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt index 385f4a6512..b2e8b9d48b 100644 --- a/docs/releases/5.0.txt +++ b/docs/releases/5.0.txt @@ -295,6 +295,9 @@ Miscellaneous * Integer fields are now validated as 64-bit integers on SQLite to match the behavior of ``sqlite3``. +* The undocumented ``Query.annotation_select_mask`` attribute is changed from a + set of strings to an ordered list of strings. + .. _deprecated-features-5.0: Features deprecated in 5.0 diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index f7615c974e..5f8441ba1b 100644 --- a/tests/postgres_tests/test_array.py +++ b/tests/postgres_tests/test_array.py @@ -466,8 +466,8 @@ class TestQuerying(PostgreSQLTestCase): ], ) sql = ctx[0]["sql"] - self.assertIn("GROUP BY 1", sql) - self.assertIn("ORDER BY 1", sql) + self.assertIn("GROUP BY 2", sql) + self.assertIn("ORDER BY 2", sql) def test_index(self): self.assertSequenceEqual( diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py index bf127ce703..71d2418f2b 100644 --- a/tests/queries/test_qs_combinators.py +++ b/tests/queries/test_qs_combinators.py @@ -246,7 +246,7 @@ class QuerySetSetOperationTests(TestCase): ) .values_list("num", "count") ) - self.assertCountEqual(qs1.union(qs2), [(1, 0), (2, 1)]) + self.assertCountEqual(qs1.union(qs2), [(1, 0), (1, 2)]) def test_union_with_extra_and_values_list(self): qs1 = ( @@ -368,6 +368,20 @@ class QuerySetSetOperationTests(TestCase): [reserved_name.pk], ) + def test_union_multiple_models_with_values_list_and_annotations(self): + ReservedName.objects.create(name="rn1", order=10) + Celebrity.objects.create(name="c1") + qs1 = ReservedName.objects.annotate(row_type=Value("rn")).values_list( + "name", "order", "row_type" + ) + qs2 = Celebrity.objects.annotate( + row_type=Value("cb"), order=Value(-10) + ).values_list("name", "order", "row_type") + self.assertSequenceEqual( + qs1.union(qs2).order_by("order"), + [("c1", -10, "cb"), ("rn1", 10, "rn")], + ) + def test_union_in_subquery(self): ReservedName.objects.bulk_create( [