[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
This commit is contained in:
Mariusz Felisiak 2020-06-08 07:21:54 +02:00
parent e8723af44b
commit be7a295141
3 changed files with 30 additions and 4 deletions

View File

@ -380,7 +380,9 @@ class BaseExpression:
Custom format for select clauses. For example, EXISTS expressions need Custom format for select clauses. For example, EXISTS expressions need
to be wrapped in CASE WHEN on Oracle. 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 @cached_property
def identity(self): def identity(self):

View File

@ -11,3 +11,6 @@ Bugfixes
* Fixed messages of ``InvalidCacheKey`` exceptions and ``CacheKeyWarning`` * Fixed messages of ``InvalidCacheKey`` exceptions and ``CacheKeyWarning``
warnings raised by cache key validation (:ticket:`31654`). 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`).

View File

@ -1,11 +1,13 @@
import datetime import datetime
from decimal import Decimal from decimal import Decimal
from unittest import skipIf
from django.core.exceptions import FieldDoesNotExist, FieldError from django.core.exceptions import FieldDoesNotExist, FieldError
from django.db import connection
from django.db.models import ( from django.db.models import (
BooleanField, CharField, Count, DateTimeField, Exists, ExpressionWrapper, BooleanField, Case, CharField, Count, DateTimeField, Exists,
F, Func, IntegerField, Max, NullBooleanField, OuterRef, Q, Subquery, Sum, ExpressionWrapper, F, Func, IntegerField, Max, NullBooleanField, OuterRef,
Value, Q, Subquery, Sum, Value, When,
) )
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
from django.db.models.functions import Length, Lower from django.db.models.functions import Length, Lower
@ -632,3 +634,22 @@ class NonAggregateAnnotationTestCase(TestCase):
datetime.date(2008, 6, 23), datetime.date(2008, 6, 23),
datetime.date(2008, 11, 3), 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},
])