mirror of https://github.com/django/django.git
Fixed #28553 -- Fixed annotation mismatch with QuerySet.values()/values_list() on compound queries.
Co-authored-by: Matthias Kestenholz <mk@feinheit.ch>
This commit is contained in:
parent
39d1e45227
commit
d6b6e5d0fd
|
@ -1087,7 +1087,12 @@ class Query(BaseExpression):
|
||||||
if select:
|
if select:
|
||||||
self.append_annotation_mask([alias])
|
self.append_annotation_mask([alias])
|
||||||
else:
|
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
|
self.annotations[alias] = annotation
|
||||||
|
|
||||||
def resolve_expression(self, query, *args, **kwargs):
|
def resolve_expression(self, query, *args, **kwargs):
|
||||||
|
@ -2341,12 +2346,12 @@ class Query(BaseExpression):
|
||||||
if names is None:
|
if names is None:
|
||||||
self.annotation_select_mask = None
|
self.annotation_select_mask = None
|
||||||
else:
|
else:
|
||||||
self.annotation_select_mask = set(names)
|
self.annotation_select_mask = list(dict.fromkeys(names))
|
||||||
self._annotation_select_cache = None
|
self._annotation_select_cache = None
|
||||||
|
|
||||||
def append_annotation_mask(self, names):
|
def append_annotation_mask(self, names):
|
||||||
if self.annotation_select_mask is not None:
|
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):
|
def set_extra_mask(self, names):
|
||||||
"""
|
"""
|
||||||
|
@ -2423,9 +2428,9 @@ class Query(BaseExpression):
|
||||||
return {}
|
return {}
|
||||||
elif self.annotation_select_mask is not None:
|
elif self.annotation_select_mask is not None:
|
||||||
self._annotation_select_cache = {
|
self._annotation_select_cache = {
|
||||||
k: v
|
k: self.annotations[k]
|
||||||
for k, v in self.annotations.items()
|
for k in self.annotation_select_mask
|
||||||
if k in self.annotation_select_mask
|
if k in self.annotations
|
||||||
}
|
}
|
||||||
return self._annotation_select_cache
|
return self._annotation_select_cache
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -295,6 +295,9 @@ Miscellaneous
|
||||||
* Integer fields are now validated as 64-bit integers on SQLite to match the
|
* Integer fields are now validated as 64-bit integers on SQLite to match the
|
||||||
behavior of ``sqlite3``.
|
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:
|
.. _deprecated-features-5.0:
|
||||||
|
|
||||||
Features deprecated in 5.0
|
Features deprecated in 5.0
|
||||||
|
|
|
@ -466,8 +466,8 @@ class TestQuerying(PostgreSQLTestCase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
sql = ctx[0]["sql"]
|
sql = ctx[0]["sql"]
|
||||||
self.assertIn("GROUP BY 1", sql)
|
self.assertIn("GROUP BY 2", sql)
|
||||||
self.assertIn("ORDER BY 1", sql)
|
self.assertIn("ORDER BY 2", sql)
|
||||||
|
|
||||||
def test_index(self):
|
def test_index(self):
|
||||||
self.assertSequenceEqual(
|
self.assertSequenceEqual(
|
||||||
|
|
|
@ -246,7 +246,7 @@ class QuerySetSetOperationTests(TestCase):
|
||||||
)
|
)
|
||||||
.values_list("num", "count")
|
.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):
|
def test_union_with_extra_and_values_list(self):
|
||||||
qs1 = (
|
qs1 = (
|
||||||
|
@ -368,6 +368,20 @@ class QuerySetSetOperationTests(TestCase):
|
||||||
[reserved_name.pk],
|
[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):
|
def test_union_in_subquery(self):
|
||||||
ReservedName.objects.bulk_create(
|
ReservedName.objects.bulk_create(
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue