diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index b9d03111c8..ff7921b520 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -144,8 +144,18 @@ class BaseExpression: if output_field is not None: self.output_field = output_field + def __getstate__(self): + # This method required only for Python 3.4. + state = self.__dict__.copy() + state.pop('convert_value', None) + return state + def get_db_converters(self, connection): - return [self.convert_value] + self.output_field.get_db_converters(connection) + return ( + [] + if self.convert_value is self._convert_value_noop else + [self.convert_value] + ) + self.output_field.get_db_converters(connection) def get_source_expressions(self): return [] @@ -274,7 +284,12 @@ class BaseExpression: raise FieldError('Expression contains mixed types. You must set output_field.') return output_field - def convert_value(self, value, expression, connection): + @staticmethod + def _convert_value_noop(value, expression, connection): + return value + + @cached_property + def convert_value(self): """ Expressions provide their own converters because users have the option of manually specifying the output_field which may be a different type @@ -282,15 +297,13 @@ class BaseExpression: """ field = self.output_field internal_type = field.get_internal_type() - if value is None: - return value - elif internal_type == 'FloatField': - return float(value) + if internal_type == 'FloatField': + return lambda value, expression, connection: None if value is None else float(value) elif internal_type.endswith('IntegerField'): - return int(value) + return lambda value, expression, connection: None if value is None else int(value) elif internal_type == 'DecimalField': - return Decimal(value) - return value + return lambda value, expression, connection: None if value is None else Decimal(value) + return self._convert_value_noop def get_lookup(self, lookup): return self.output_field.get_lookup(lookup)