diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 58e945dd44..5e3c7cab82 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -1501,6 +1501,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: diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 96d10b9eda..27310e5d9f 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -160,7 +160,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: diff --git a/docs/releases/4.1.2.txt b/docs/releases/4.1.2.txt index 4659558f3d..96c2fefcdc 100644 --- a/docs/releases/4.1.2.txt +++ b/docs/releases/4.1.2.txt @@ -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`). diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py index 75a4e0d022..5ec12ccd64 100644 --- a/tests/aggregation/tests.py +++ b/tests/aggregation/tests.py @@ -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.