summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2017-07-27 02:26:58 +0200
committerTim Graham <timograham@gmail.com>2017-07-26 20:26:58 -0400
commit8e41373c81cbd914d84b362ca4c85d3ed4fcff43 (patch)
tree931a46b9ef2b7b5115e9d4d2553f19b3a6401549
parentef9344b3a5b91f6b442830923dd28d779fdf8019 (diff)
Allowed database backends to specify data types for Cast().
A small refactor ahead of refs #28371.
-rw-r--r--django/db/backends/base/operations.py4
-rw-r--r--django/db/backends/mysql/operations.py9
-rw-r--r--django/db/models/fields/__init__.py7
-rw-r--r--django/db/models/functions/base.py21
4 files changed, 21 insertions, 20 deletions
diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py
index dea15c2ad1..effdffd6e7 100644
--- a/django/db/backends/base/operations.py
+++ b/django/db/backends/base/operations.py
@@ -32,6 +32,10 @@ class BaseDatabaseOperations:
'intersection': 'INTERSECT',
'difference': 'EXCEPT',
}
+ # Mapping of Field.get_internal_type() (typically the model field's class
+ # name) to the data type to use for the Cast() function, if different from
+ # DatabaseWrapper.data_types.
+ cast_data_types = {}
def __init__(self, connection):
self.connection = connection
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py
index 405aa4bd45..71592234aa 100644
--- a/django/db/backends/mysql/operations.py
+++ b/django/db/backends/mysql/operations.py
@@ -15,6 +15,15 @@ class DatabaseOperations(BaseDatabaseOperations):
PositiveSmallIntegerField=(0, 65535),
PositiveIntegerField=(0, 4294967295),
)
+ cast_data_types = {
+ 'CharField': 'char(%(max_length)s)',
+ 'IntegerField': 'signed integer',
+ 'BigIntegerField': 'signed integer',
+ 'SmallIntegerField': 'signed integer',
+ 'FloatField': 'signed',
+ 'PositiveIntegerField': 'unsigned integer',
+ 'PositiveSmallIntegerField': 'unsigned integer',
+ }
def date_extract_sql(self, lookup_type, field_name):
# http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index b24d6b412f..5963339dad 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -656,6 +656,13 @@ class Field(RegisterLookupMixin):
"""
return self.db_type(connection)
+ def cast_db_type(self, connection):
+ """Return the data type to use in the Cast() function."""
+ db_type = connection.ops.cast_data_types.get(self.get_internal_type())
+ if db_type:
+ return db_type % self.db_type_parameters(connection)
+ return self.db_type(connection)
+
def db_parameters(self, connection):
"""
Extension of db_type(), providing a range of different return values
diff --git a/django/db/models/functions/base.py b/django/db/models/functions/base.py
index a965f4107c..378a9504d2 100644
--- a/django/db/models/functions/base.py
+++ b/django/db/models/functions/base.py
@@ -9,32 +9,13 @@ class Cast(Func):
function = 'CAST'
template = '%(function)s(%(expressions)s AS %(db_type)s)'
- mysql_types = {
- fields.CharField: 'char(%(max_length)s)',
- fields.IntegerField: 'signed integer',
- fields.BigIntegerField: 'signed integer',
- fields.SmallIntegerField: 'signed integer',
- fields.FloatField: 'signed',
- fields.PositiveIntegerField: 'unsigned integer',
- fields.PositiveSmallIntegerField: 'unsigned integer',
- }
-
def __init__(self, expression, output_field):
super().__init__(expression, output_field=output_field)
def as_sql(self, compiler, connection, **extra_context):
- if 'db_type' not in extra_context:
- extra_context['db_type'] = self.output_field.db_type(connection)
+ extra_context['db_type'] = self.output_field.cast_db_type(connection)
return super().as_sql(compiler, connection, **extra_context)
- def as_mysql(self, compiler, connection):
- extra_context = {}
- output_field_class = type(self.output_field)
- if output_field_class in self.mysql_types:
- data = self.output_field.db_type_parameters(connection)
- extra_context['db_type'] = self.mysql_types[output_field_class] % data
- return self.as_sql(compiler, connection, **extra_context)
-
def as_postgresql(self, compiler, connection):
# CAST would be valid too, but the :: shortcut syntax is more readable.
return self.as_sql(compiler, connection, template='%(expressions)s::%(db_type)s')