Permalink
Browse files

Fixed #28382 -- Prevented BaseExpression._output_field from being set…

… if _resolve_output_field() fails.
  • Loading branch information...
1 parent 306b961 commit 29769a9942b08c86397692fa164396a670a4e1ec @sir-sigurd sir-sigurd committed with timgraham Jul 7, 2017
Showing with 14 additions and 17 deletions.
  1. +2 −2 django/db/models/aggregates.py
  2. +6 −13 django/db/models/expressions.py
  3. +6 −2 tests/aggregation/tests.py
@@ -44,8 +44,8 @@ class Avg(Aggregate):
def _resolve_output_field(self):
source_field = self.get_source_fields()[0]
if isinstance(source_field, (IntegerField, DecimalField)):
- self._output_field = FloatField()
- super()._resolve_output_field()
+ return FloatField()
+ return super()._resolve_output_field()
def as_oracle(self, compiler, connection):
if self.output_field.get_internal_type() == 'DurationField':
@@ -236,7 +236,7 @@ def _output_field_or_none(self):
None values.
"""
if self._output_field is None:
- self._resolve_output_field()
+ self._output_field = self._resolve_output_field()
return self._output_field
def _resolve_output_field(self):
@@ -253,18 +253,11 @@ def _resolve_output_field(self):
this check. If all sources are `None`, then an error will be thrown
higher up the stack in the `output_field` property.
"""
- if self._output_field is None:
- sources = self.get_source_fields()
- num_sources = len(sources)
- if num_sources == 0:
- self._output_field = None
- else:
- for source in sources:
- if self._output_field is None:
- self._output_field = source
- if source is not None and not isinstance(self._output_field, source.__class__):
- raise FieldError(
- "Expression contains mixed types. You must set output_field")
+ sources_iter = (source for source in self.get_source_fields() if source is not None)
+ for output_field in sources_iter:
+ if any(not isinstance(output_field, source.__class__) for source in sources_iter):
+ raise FieldError('Expression contains mixed types. You must set output_field.')
+ return output_field
def convert_value(self, value, expression, connection, context):
"""
@@ -965,8 +965,12 @@ def test_order_of_precedence(self):
self.assertEqual(p2, {'avg_price': Approximate(53.39, places=2)})
def test_combine_different_types(self):
- with self.assertRaisesMessage(FieldError, 'Expression contains mixed types. You must set output_field'):
- Book.objects.annotate(sums=Sum('rating') + Sum('pages') + Sum('price')).get(pk=self.b4.pk)
+ msg = 'Expression contains mixed types. You must set output_field.'
+ qs = Book.objects.annotate(sums=Sum('rating') + Sum('pages') + Sum('price'))
+ with self.assertRaisesMessage(FieldError, msg):
+ qs.first()
+ with self.assertRaisesMessage(FieldError, msg):
+ qs.first()
b1 = Book.objects.annotate(sums=Sum(F('rating') + F('pages') + F('price'),
output_field=IntegerField())).get(pk=self.b4.pk)

0 comments on commit 29769a9

Please sign in to comment.