[3.1.x] Fixed #31660 -- Fixed queryset crash when grouping by m2o relation.

Regression in 3a941230c8.

Thanks Tomasz Szymański for the report.
Backport of 78ad4b4b02 from master
This commit is contained in:
Mariusz Felisiak 2020-06-08 07:21:54 +02:00
parent 21adaffb6e
commit df9b9de6b0
3 changed files with 30 additions and 4 deletions

View File

@ -383,7 +383,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},
])