mirror of
https://github.com/django/django.git
synced 2025-01-18 14:24:39 +00:00
Fixed #31568 -- Fixed alias reference when aggregating over multiple subqueries.
691def10a0197d83d2d108bd9043b0916d0f09b4 made all Subquery() instances equal to each other which broke aggregation subquery pushdown which relied on object equality to determine which alias it should select. Subquery.__eq__() will be fixed in an another commit but Query.rewrite_cols() should haved used object identity from the start. Refs #30727, #30188. Thanks Makina Corpus for the report.
This commit is contained in:
parent
42c08ee465
commit
adfbf653dc
@ -390,7 +390,7 @@ class Query(BaseExpression):
|
|||||||
else:
|
else:
|
||||||
# Reuse aliases of expressions already selected in subquery.
|
# Reuse aliases of expressions already selected in subquery.
|
||||||
for col_alias, selected_annotation in self.annotation_select.items():
|
for col_alias, selected_annotation in self.annotation_select.items():
|
||||||
if selected_annotation == expr:
|
if selected_annotation is expr:
|
||||||
new_expr = Ref(col_alias, expr)
|
new_expr = Ref(col_alias, expr)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -15,3 +15,6 @@ Bugfixes
|
|||||||
* Fixed a regression in Django 3.0 where ``QuerySet.values()`` and
|
* Fixed a regression in Django 3.0 where ``QuerySet.values()`` and
|
||||||
``values_list()`` crashed if a queryset contained an aggregation and a
|
``values_list()`` crashed if a queryset contained an aggregation and a
|
||||||
subquery annotation (:ticket:`31566`).
|
subquery annotation (:ticket:`31566`).
|
||||||
|
|
||||||
|
* Fixed a regression in Django 3.0 where aggregates used wrong annotations when
|
||||||
|
a queryset has multiple subqueries annotations (:ticket:`31568`).
|
||||||
|
@ -2,7 +2,8 @@ import datetime
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
Avg, Case, Count, F, OuterRef, Q, StdDev, Subquery, Sum, Variance, When,
|
Avg, Case, Count, Exists, F, Max, OuterRef, Q, StdDev, Subquery, Sum,
|
||||||
|
Variance, When,
|
||||||
)
|
)
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import Approximate
|
from django.test.utils import Approximate
|
||||||
@ -120,3 +121,23 @@ class FilteredAggregateTests(TestCase):
|
|||||||
cnt=Count('pk', filter=Q(earliest_book_year=2008)),
|
cnt=Count('pk', filter=Q(earliest_book_year=2008)),
|
||||||
)
|
)
|
||||||
self.assertEqual(aggs['cnt'], 2)
|
self.assertEqual(aggs['cnt'], 2)
|
||||||
|
|
||||||
|
def test_filtered_aggregate_ref_multiple_subquery_annotation(self):
|
||||||
|
aggregate = Book.objects.values('publisher').annotate(
|
||||||
|
has_authors=Exists(
|
||||||
|
Book.authors.through.objects.filter(book=OuterRef('pk')),
|
||||||
|
),
|
||||||
|
authors_have_other_books=Exists(
|
||||||
|
Book.objects.filter(
|
||||||
|
authors__in=Author.objects.filter(
|
||||||
|
book_contact_set=OuterRef(OuterRef('pk')),
|
||||||
|
)
|
||||||
|
).exclude(pk=OuterRef('pk')),
|
||||||
|
),
|
||||||
|
).aggregate(
|
||||||
|
max_rating=Max(
|
||||||
|
'rating',
|
||||||
|
filter=Q(has_authors=True, authors_have_other_books=False),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(aggregate, {'max_rating': 4.5})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user