Fixed #18757, #14462, #21565 -- Reworked database-python type conversions

Complete rework of translating data values from database

Deprecation of SubfieldBase, removal of resolve_columns and
convert_values in favour of a more general converter based approach and
public API Field.from_db_value(). Now works seamlessly with aggregation,
.values() and raw queries.

Thanks to akaariai in particular for extensive advice and inspiration,
also to shaib, manfre and timograham for their reviews.
This commit is contained in:
Marc Tamlyn 2014-08-12 13:08:40 +01:00
parent 89559bcfb0
commit e9103402c0
35 changed files with 443 additions and 521 deletions

View file

@ -263,27 +263,36 @@ class DatabaseOperations(BaseDatabaseOperations):
return six.text_type(value)
def convert_values(self, value, field):
"""SQLite returns floats when it should be returning decimals,
and gets dates and datetimes wrong.
For consistency with other backends, coerce when required.
"""
if value is None:
return None
internal_type = field.get_internal_type()
if internal_type == 'DecimalField':
return backend_utils.typecast_decimal(field.format_number(value))
elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
return int(value)
def get_db_converters(self, internal_type):
converters = super(DatabaseOperations, self).get_db_converters(internal_type)
if internal_type == 'DateTimeField':
converters.append(self.convert_datetimefield_value)
elif internal_type == 'DateField':
return parse_date(value)
elif internal_type == 'DateTimeField':
return parse_datetime_with_timezone_support(value)
converters.append(self.convert_datefield_value)
elif internal_type == 'TimeField':
return parse_time(value)
converters.append(self.convert_timefield_value)
elif internal_type == 'DecimalField':
converters.append(self.convert_decimalfield_value)
return converters
# No field, or the field isn't known to be a decimal or integer
def convert_decimalfield_value(self, value, field):
if value is not None:
value = backend_utils.typecast_decimal(field.format_number(value))
return value
def convert_datefield_value(self, value, field):
if value is not None and not isinstance(value, datetime.date):
value = parse_date(value)
return value
def convert_datetimefield_value(self, value, field):
if value is not None and not isinstance(value, datetime.datetime):
value = parse_datetime_with_timezone_support(value)
return value
def convert_timefield_value(self, value, field):
if value is not None and not isinstance(value, datetime.time):
value = parse_time(value)
return value
def bulk_insert_sql(self, fields, num_values):