From 720de4d0441fcfdb543051389c70efbe66ed962a Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Sat, 21 Dec 2019 23:22:49 -0500 Subject: [PATCH] Fixed #31109 -- Disabled grouping by aliases on QuerySet.exists(). Clearing the SELECT clause in Query.has_results was orphaning GROUP BY references to it. Thanks Thierry Bastian for the report and Baptiste Mispelon for the bisect. Regression in fb3f034f1c63160c0ff13c609acd01c18be12f80. --- django/db/models/sql/query.py | 8 ++++++-- docs/releases/3.0.2.txt | 3 +++ tests/aggregation/tests.py | 10 ++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index ac4822e18a..fc423b6acf 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -526,7 +526,9 @@ class Query(BaseExpression): if not q.distinct: if q.group_by is True: q.add_fields((f.attname for f in self.model._meta.concrete_fields), False) - q.set_group_by() + # Disable GROUP BY aliases to avoid orphaning references to the + # SELECT clause which is about to be cleared. + q.set_group_by(allow_aliases=False) q.clear_select_clause() q.clear_ordering(True) q.set_limits(high=1) @@ -1916,7 +1918,7 @@ class Query(BaseExpression): if force_empty: self.default_ordering = False - def set_group_by(self): + def set_group_by(self, allow_aliases=True): """ Expand the GROUP BY clause required by the query. @@ -1938,6 +1940,8 @@ class Query(BaseExpression): warnings.warn(msg, category=RemovedInDjango40Warning) group_by_cols = annotation.get_group_by_cols() else: + if not allow_aliases: + alias = None group_by_cols = annotation.get_group_by_cols(alias=alias) group_by.extend(group_by_cols) self.group_by = tuple(group_by) diff --git a/docs/releases/3.0.2.txt b/docs/releases/3.0.2.txt index 53b066838a..ccc82b18ae 100644 --- a/docs/releases/3.0.2.txt +++ b/docs/releases/3.0.2.txt @@ -11,3 +11,6 @@ Bugfixes * Fixed a regression in Django 3.0 that didn't include columns referenced by a ``Subquery()`` in the ``GROUP BY`` clause (:ticket:`31094`). + +* Fixed a regression in Django 3.0 where ``QuerySet.exists()`` crashed if a + queryset contained an aggregation over a ``Subquery()`` (:ticket:`31109`). diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py index ecbe81c151..dd30f57bed 100644 --- a/tests/aggregation/tests.py +++ b/tests/aggregation/tests.py @@ -1141,6 +1141,16 @@ class AggregateTestCase(TestCase): # The GROUP BY should not be by alias either. self.assertEqual(ctx[0]['sql'].lower().count('latest_book_pubdate'), 1) + def test_aggregation_subquery_annotation_exists(self): + latest_book_pubdate_qs = Book.objects.filter( + publisher=OuterRef('pk') + ).order_by('-pubdate').values('pubdate')[:1] + publisher_qs = Publisher.objects.annotate( + latest_book_pubdate=Subquery(latest_book_pubdate_qs), + count=Count('book'), + ) + self.assertTrue(publisher_qs.exists()) + @skipUnlessDBFeature('supports_subqueries_in_group_by') def test_group_by_subquery_annotation(self): """