From 42f5f2d76b19ee36ca659c6141b8a8197387c918 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 11 Jun 2020 11:29:14 +0200 Subject: [PATCH] [3.1.x] Fixed #31659 -- Made ExpressionWrapper preserve output_field for combined expressions. Regression in df32fd42b84cc6dbba173201f244491b0d154a63. Thanks Simon Charette for the review. Backport of aeb8996a6706cad3e96d8221760c1cb408ee7ed9 from master --- django/db/models/expressions.py | 3 +++ tests/annotations/tests.py | 8 ++++++++ tests/expressions/tests.py | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index ee786eb763..8d7d72a52a 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -857,6 +857,9 @@ class ExpressionWrapper(Expression): def __init__(self, expression, output_field): super().__init__(output_field=output_field) + if getattr(expression, '_output_field_or_none', True) is None: + expression = expression.copy() + expression.output_field = output_field self.expression = expression def set_source_expressions(self, exprs): diff --git a/tests/annotations/tests.py b/tests/annotations/tests.py index c1ac0516ac..9f35074934 100644 --- a/tests/annotations/tests.py +++ b/tests/annotations/tests.py @@ -170,6 +170,14 @@ class NonAggregateAnnotationTestCase(TestCase): self.assertEqual(book.is_book, 1) self.assertEqual(book.rating_count, 1) + def test_combined_expression_annotation_with_aggregation(self): + book = Book.objects.annotate( + combined=ExpressionWrapper(Value(3) * Value(4), output_field=IntegerField()), + rating_count=Count('rating'), + ).first() + self.assertEqual(book.combined, 12) + self.assertEqual(book.rating_count, 1) + def test_aggregate_over_annotation(self): agg = Author.objects.annotate(other_age=F('age')).aggregate(otherage_sum=Sum('other_age')) other_agg = Author.objects.aggregate(age_sum=Sum('age')) diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index 57e4c8ebc7..459a87797d 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -1837,4 +1837,6 @@ class ExpressionWrapperTests(SimpleTestCase): def test_non_empty_group_by(self): expr = ExpressionWrapper(Lower(Value('f')), output_field=IntegerField()) - self.assertEqual(expr.get_group_by_cols(alias=None), [expr.expression]) + group_by_cols = expr.get_group_by_cols(alias=None) + self.assertEqual(group_by_cols, [expr.expression]) + self.assertEqual(group_by_cols[0].output_field, expr.output_field)