summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2020-06-08 07:21:54 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-06-08 07:23:33 +0200
commitbe7a295141337189b9eceea506489bdfe07f199e (patch)
treef167ddedb766a5ba48c0305c2bd15c7fc77130aa
parente8723af44be82968f573a00277f40016b049f08e (diff)
[3.0.x] Fixed #31660 -- Fixed queryset crash when grouping by m2o relation.
Regression in 3a941230c85b2702a5e1cd97e17251ce21057efa. Thanks Tomasz SzymaƄski for the report. Backport of 78ad4b4b0201003792bfdbf1a7781cbc9ee03539 from master
-rw-r--r--django/db/models/expressions.py4
-rw-r--r--docs/releases/3.0.8.txt3
-rw-r--r--tests/annotations/tests.py27
3 files changed, 30 insertions, 4 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 7b68e1108e..29649313e5 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -380,7 +380,9 @@ class BaseExpression:
Custom format for select clauses. For example, EXISTS expressions need
to be wrapped in CASE WHEN on Oracle.
"""
- return self.output_field.select_format(compiler, sql, params)
+ if hasattr(self.output_field, 'select_format'):
+ return self.output_field.select_format(compiler, sql, params)
+ return sql, params
@cached_property
def identity(self):
diff --git a/docs/releases/3.0.8.txt b/docs/releases/3.0.8.txt
index e355f0a0ff..d21eac37c8 100644
--- a/docs/releases/3.0.8.txt
+++ b/docs/releases/3.0.8.txt
@@ -11,3 +11,6 @@ Bugfixes
* Fixed messages of ``InvalidCacheKey`` exceptions and ``CacheKeyWarning``
warnings raised by cache key validation (:ticket:`31654`).
+
+* Fixed a regression in Django 3.0.7 that caused a queryset crash when grouping
+ by a many-to-one relationship (:ticket:`31660`).
diff --git a/tests/annotations/tests.py b/tests/annotations/tests.py
index 0064b14ed0..0c6381c773 100644
--- a/tests/annotations/tests.py
+++ b/tests/annotations/tests.py
@@ -1,11 +1,13 @@
import datetime
from decimal import Decimal
+from unittest import skipIf
from django.core.exceptions import FieldDoesNotExist, FieldError
+from django.db import connection
from django.db.models import (
- BooleanField, CharField, Count, DateTimeField, Exists, ExpressionWrapper,
- F, Func, IntegerField, Max, NullBooleanField, OuterRef, Q, Subquery, Sum,
- Value,
+ BooleanField, Case, CharField, Count, DateTimeField, Exists,
+ ExpressionWrapper, F, Func, IntegerField, Max, NullBooleanField, OuterRef,
+ Q, Subquery, Sum, Value, When,
)
from django.db.models.expressions import RawSQL
from django.db.models.functions import Length, Lower
@@ -632,3 +634,22 @@ class NonAggregateAnnotationTestCase(TestCase):
datetime.date(2008, 6, 23),
datetime.date(2008, 11, 3),
])
+
+ @skipIf(
+ connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode,
+ 'GROUP BY optimization does not work properly when ONLY_FULL_GROUP_BY '
+ 'mode is enabled on MySQL, see #31331.',
+ )
+ def test_annotation_aggregate_with_m2o(self):
+ qs = Author.objects.filter(age__lt=30).annotate(
+ max_pages=Case(
+ When(book_contact_set__isnull=True, then=Value(0)),
+ default=Max(F('book__pages')),
+ output_field=IntegerField(),
+ ),
+ ).values('name', 'max_pages')
+ self.assertCountEqual(qs, [
+ {'name': 'James Bennett', 'max_pages': 300},
+ {'name': 'Paul Bissex', 'max_pages': 0},
+ {'name': 'Wesley J. Chun', 'max_pages': 0},
+ ])