[4.1.x] Fixed #33992 -- Fixed queryset crash when aggregating over a group containing Exists.
A more in-depth solution is likely to make sure that we always GROUP BY selected annotations or revisit how we use Query.exists() in the Exists expression but that requires extra work that isn't suitable for a backport. Regression ine5a92d400a
. Thanks Fernando Flores Villaça for the report. Backport of32536b1324
from main
This commit is contained in:
parent
7ba9a44831
commit
e0f14d8389
|
@ -1481,6 +1481,14 @@ class Exists(Subquery):
|
|||
clone.negated = not self.negated
|
||||
return clone
|
||||
|
||||
def get_group_by_cols(self, alias=None):
|
||||
# self.query only gets limited to a single row in the .exists() call
|
||||
# from self.as_sql() so deferring to Query.get_group_by_cols() is
|
||||
# inappropriate.
|
||||
if alias is None:
|
||||
return [self]
|
||||
return super().get_group_by_cols(alias)
|
||||
|
||||
def as_sql(self, compiler, connection, template=None, **extra_context):
|
||||
query = self.query.exists(using=connection.alias)
|
||||
try:
|
||||
|
|
|
@ -154,7 +154,10 @@ class SQLCompiler:
|
|||
expressions = self.collapse_group_by(expressions, having_group_by)
|
||||
|
||||
for expr in expressions:
|
||||
sql, params = self.compile(expr)
|
||||
try:
|
||||
sql, params = self.compile(expr)
|
||||
except EmptyResultSet:
|
||||
continue
|
||||
sql, params = expr.select_format(self, sql, params)
|
||||
params_hash = make_hashable(params)
|
||||
if (sql, params_hash) not in seen:
|
||||
|
|
|
@ -11,3 +11,7 @@ Bugfixes
|
|||
|
||||
* Fixed a regression in Django 4.1 that caused a migration crash on PostgreSQL
|
||||
when adding a model with ``ExclusionConstraint`` (:ticket:`33982`).
|
||||
|
||||
* Fixed a regression in Django 4.1 that caused aggregation over a queryset that
|
||||
contained an ``Exists`` annotation to crash due to too many selected columns
|
||||
(:ticket:`33992`).
|
||||
|
|
|
@ -1663,6 +1663,17 @@ class AggregateTestCase(TestCase):
|
|||
).values_list("publisher_count", flat=True)
|
||||
self.assertSequenceEqual(books_breakdown, [1] * 6)
|
||||
|
||||
def test_aggregation_exists_multivalued_outeref(self):
|
||||
self.assertCountEqual(
|
||||
Publisher.objects.annotate(
|
||||
books_exists=Exists(
|
||||
Book.objects.filter(publisher=OuterRef("book__publisher"))
|
||||
),
|
||||
books_count=Count("book"),
|
||||
),
|
||||
Publisher.objects.all(),
|
||||
)
|
||||
|
||||
def test_filter_in_subquery_or_aggregation(self):
|
||||
"""
|
||||
Filtering against an aggregate requires the usage of the HAVING clause.
|
||||
|
|
Loading…
Reference in New Issue