summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2014-12-29 15:14:40 -0500
committerTim Graham <timograham@gmail.com>2014-12-31 08:29:17 -0500
commit93d73dac91104fd82d44b0dd4521cfa4f31e02aa (patch)
tree10dac1f7300e934118c425072463b07b23afda03
parent32ca159c96339b4856837d7abec376a575ec44ab (diff)
Moved DatabaseCreation.data_types properties to DatabaseWrapper.
refs #22340.
-rw-r--r--django/db/backends/__init__.py6
-rw-r--r--django/db/backends/creation.py4
-rw-r--r--django/db/backends/mysql/base.py39
-rw-r--r--django/db/backends/mysql/creation.py39
-rw-r--r--django/db/backends/oracle/base.py42
-rw-r--r--django/db/backends/oracle/creation.py43
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py35
-rw-r--r--django/db/backends/postgresql_psycopg2/creation.py36
-rw-r--r--django/db/backends/sqlite3/base.py33
-rw-r--r--django/db/backends/sqlite3/creation.py33
-rw-r--r--django/db/models/fields/__init__.py6
-rw-r--r--docs/releases/1.8.txt10
-rw-r--r--tests/commands_sql/tests.py2
13 files changed, 169 insertions, 159 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index b13fb1e9d5..3c99819218 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -39,6 +39,12 @@ class BaseDatabaseWrapper(object):
"""
Represents a database connection.
"""
+ # Mapping of Field objects to their column types.
+ data_types = {}
+ # Mapping of Field objects to their SQL suffix such as AUTOINCREMENT.
+ data_types_suffix = {}
+ # Mapping of Field objects to their SQL for CHECK constraints.
+ data_type_check_constraints = {}
ops = None
vendor = 'unknown'
SchemaEditorClass = None
diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py
index 6ccc6a3236..5e0248d4df 100644
--- a/django/db/backends/creation.py
+++ b/django/db/backends/creation.py
@@ -26,10 +26,6 @@ class BaseDatabaseCreation(object):
Fields, the SQL used to create and destroy tables, and the creation and
destruction of test databases.
"""
- data_types = {}
- data_types_suffix = {}
- data_type_check_constraints = {}
-
def __init__(self, connection):
self.connection = connection
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 6cfb136879..3b258d35f3 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -415,6 +415,45 @@ class DatabaseOperations(BaseDatabaseOperations):
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'mysql'
+ # This dictionary maps Field objects to their associated MySQL column
+ # types, as strings. Column-type strings can contain format strings; they'll
+ # be interpolated against the values of Field.__dict__ before being output.
+ # If a column type is set to None, it won't be included in the output.
+ _data_types = {
+ 'AutoField': 'integer AUTO_INCREMENT',
+ 'BinaryField': 'longblob',
+ 'BooleanField': 'bool',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
+ 'DateField': 'date',
+ 'DateTimeField': 'datetime',
+ 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
+ 'DurationField': 'bigint',
+ 'FileField': 'varchar(%(max_length)s)',
+ 'FilePathField': 'varchar(%(max_length)s)',
+ 'FloatField': 'double precision',
+ 'IntegerField': 'integer',
+ 'BigIntegerField': 'bigint',
+ 'IPAddressField': 'char(15)',
+ 'GenericIPAddressField': 'char(39)',
+ 'NullBooleanField': 'bool',
+ 'OneToOneField': 'integer',
+ 'PositiveIntegerField': 'integer UNSIGNED',
+ 'PositiveSmallIntegerField': 'smallint UNSIGNED',
+ 'SlugField': 'varchar(%(max_length)s)',
+ 'SmallIntegerField': 'smallint',
+ 'TextField': 'longtext',
+ 'TimeField': 'time',
+ 'UUIDField': 'char(32)',
+ }
+
+ @cached_property
+ def data_types(self):
+ if self.features.supports_microsecond_precision:
+ return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
+ else:
+ return self._data_types
+
operators = {
'exact': '= %s',
'iexact': 'LIKE %s',
diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py
index efa0ea06e7..8cce569058 100644
--- a/django/db/backends/mysql/creation.py
+++ b/django/db/backends/mysql/creation.py
@@ -1,46 +1,7 @@
from django.db.backends.creation import BaseDatabaseCreation
-from django.utils.functional import cached_property
class DatabaseCreation(BaseDatabaseCreation):
- # This dictionary maps Field objects to their associated MySQL column
- # types, as strings. Column-type strings can contain format strings; they'll
- # be interpolated against the values of Field.__dict__ before being output.
- # If a column type is set to None, it won't be included in the output.
- _data_types = {
- 'AutoField': 'integer AUTO_INCREMENT',
- 'BinaryField': 'longblob',
- 'BooleanField': 'bool',
- 'CharField': 'varchar(%(max_length)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
- 'DateField': 'date',
- 'DateTimeField': 'datetime',
- 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'DurationField': 'bigint',
- 'FileField': 'varchar(%(max_length)s)',
- 'FilePathField': 'varchar(%(max_length)s)',
- 'FloatField': 'double precision',
- 'IntegerField': 'integer',
- 'BigIntegerField': 'bigint',
- 'IPAddressField': 'char(15)',
- 'GenericIPAddressField': 'char(39)',
- 'NullBooleanField': 'bool',
- 'OneToOneField': 'integer',
- 'PositiveIntegerField': 'integer UNSIGNED',
- 'PositiveSmallIntegerField': 'smallint UNSIGNED',
- 'SlugField': 'varchar(%(max_length)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'longtext',
- 'TimeField': 'time',
- 'UUIDField': 'char(32)',
- }
-
- @cached_property
- def data_types(self):
- if self.connection.features.supports_microsecond_precision:
- return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
- else:
- return self._data_types
def sql_table_creation_suffix(self):
suffix = []
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index aadc7c9682..ea08ff466c 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -575,6 +575,48 @@ class _UninitializedOperatorsDescriptor(object):
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'oracle'
+ # This dictionary maps Field objects to their associated Oracle column
+ # types, as strings. Column-type strings can contain format strings; they'll
+ # be interpolated against the values of Field.__dict__ before being output.
+ # If a column type is set to None, it won't be included in the output.
+ #
+ # Any format strings starting with "qn_" are quoted before being used in the
+ # output (the "qn_" prefix is stripped before the lookup is performed.
+ data_types = {
+ 'AutoField': 'NUMBER(11)',
+ 'BinaryField': 'BLOB',
+ 'BooleanField': 'NUMBER(1)',
+ 'CharField': 'NVARCHAR2(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)',
+ 'DateField': 'DATE',
+ 'DateTimeField': 'TIMESTAMP',
+ 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
+ 'DurationField': 'INTERVAL DAY(9) TO SECOND(6)',
+ 'FileField': 'NVARCHAR2(%(max_length)s)',
+ 'FilePathField': 'NVARCHAR2(%(max_length)s)',
+ 'FloatField': 'DOUBLE PRECISION',
+ 'IntegerField': 'NUMBER(11)',
+ 'BigIntegerField': 'NUMBER(19)',
+ 'IPAddressField': 'VARCHAR2(15)',
+ 'GenericIPAddressField': 'VARCHAR2(39)',
+ 'NullBooleanField': 'NUMBER(1)',
+ 'OneToOneField': 'NUMBER(11)',
+ 'PositiveIntegerField': 'NUMBER(11)',
+ 'PositiveSmallIntegerField': 'NUMBER(11)',
+ 'SlugField': 'NVARCHAR2(%(max_length)s)',
+ 'SmallIntegerField': 'NUMBER(11)',
+ 'TextField': 'NCLOB',
+ 'TimeField': 'TIMESTAMP',
+ 'URLField': 'VARCHAR2(%(max_length)s)',
+ 'UUIDField': 'VARCHAR2(32)',
+ }
+ data_type_check_constraints = {
+ 'BooleanField': '%(qn_column)s IN (0,1)',
+ 'NullBooleanField': '(%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL)',
+ 'PositiveIntegerField': '%(qn_column)s >= 0',
+ 'PositiveSmallIntegerField': '%(qn_column)s >= 0',
+ }
+
operators = _UninitializedOperatorsDescriptor()
_standard_operators = {
diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py
index e91cecf7d5..1c1c435fa1 100644
--- a/django/db/backends/oracle/creation.py
+++ b/django/db/backends/oracle/creation.py
@@ -12,49 +12,6 @@ PASSWORD = 'Im_a_lumberjack'
class DatabaseCreation(BaseDatabaseCreation):
- # This dictionary maps Field objects to their associated Oracle column
- # types, as strings. Column-type strings can contain format strings; they'll
- # be interpolated against the values of Field.__dict__ before being output.
- # If a column type is set to None, it won't be included in the output.
- #
- # Any format strings starting with "qn_" are quoted before being used in the
- # output (the "qn_" prefix is stripped before the lookup is performed.
-
- data_types = {
- 'AutoField': 'NUMBER(11)',
- 'BinaryField': 'BLOB',
- 'BooleanField': 'NUMBER(1)',
- 'CharField': 'NVARCHAR2(%(max_length)s)',
- 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)',
- 'DateField': 'DATE',
- 'DateTimeField': 'TIMESTAMP',
- 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
- 'DurationField': 'INTERVAL DAY(9) TO SECOND(6)',
- 'FileField': 'NVARCHAR2(%(max_length)s)',
- 'FilePathField': 'NVARCHAR2(%(max_length)s)',
- 'FloatField': 'DOUBLE PRECISION',
- 'IntegerField': 'NUMBER(11)',
- 'BigIntegerField': 'NUMBER(19)',
- 'IPAddressField': 'VARCHAR2(15)',
- 'GenericIPAddressField': 'VARCHAR2(39)',
- 'NullBooleanField': 'NUMBER(1)',
- 'OneToOneField': 'NUMBER(11)',
- 'PositiveIntegerField': 'NUMBER(11)',
- 'PositiveSmallIntegerField': 'NUMBER(11)',
- 'SlugField': 'NVARCHAR2(%(max_length)s)',
- 'SmallIntegerField': 'NUMBER(11)',
- 'TextField': 'NCLOB',
- 'TimeField': 'TIMESTAMP',
- 'URLField': 'VARCHAR2(%(max_length)s)',
- 'UUIDField': 'VARCHAR2(32)',
- }
-
- data_type_check_constraints = {
- 'BooleanField': '%(qn_column)s IN (0,1)',
- 'NullBooleanField': '(%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL)',
- 'PositiveIntegerField': '%(qn_column)s >= 0',
- 'PositiveSmallIntegerField': '%(qn_column)s >= 0',
- }
def _create_test_db(self, verbosity=1, autoclobber=False, keepdb=False):
parameters = self._get_test_db_params()
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index c1dfa54c95..8b45b5d73e 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -71,6 +71,41 @@ class DatabaseFeatures(BaseDatabaseFeatures):
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'postgresql'
+ # This dictionary maps Field objects to their associated PostgreSQL column
+ # types, as strings. Column-type strings can contain format strings; they'll
+ # be interpolated against the values of Field.__dict__ before being output.
+ # If a column type is set to None, it won't be included in the output.
+ data_types = {
+ 'AutoField': 'serial',
+ 'BinaryField': 'bytea',
+ 'BooleanField': 'boolean',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
+ 'DateField': 'date',
+ 'DateTimeField': 'timestamp with time zone',
+ 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
+ 'DurationField': 'interval',
+ 'FileField': 'varchar(%(max_length)s)',
+ 'FilePathField': 'varchar(%(max_length)s)',
+ 'FloatField': 'double precision',
+ 'IntegerField': 'integer',
+ 'BigIntegerField': 'bigint',
+ 'IPAddressField': 'inet',
+ 'GenericIPAddressField': 'inet',
+ 'NullBooleanField': 'boolean',
+ 'OneToOneField': 'integer',
+ 'PositiveIntegerField': 'integer',
+ 'PositiveSmallIntegerField': 'smallint',
+ 'SlugField': 'varchar(%(max_length)s)',
+ 'SmallIntegerField': 'smallint',
+ 'TextField': 'text',
+ 'TimeField': 'time',
+ 'UUIDField': 'uuid',
+ }
+ data_type_check_constraints = {
+ 'PositiveIntegerField': '"%(column)s" >= 0',
+ 'PositiveSmallIntegerField': '"%(column)s" >= 0',
+ }
operators = {
'exact': '= %s',
'iexact': '= UPPER(%s)',
diff --git a/django/db/backends/postgresql_psycopg2/creation.py b/django/db/backends/postgresql_psycopg2/creation.py
index 45ce939165..353d0b794f 100644
--- a/django/db/backends/postgresql_psycopg2/creation.py
+++ b/django/db/backends/postgresql_psycopg2/creation.py
@@ -3,42 +3,6 @@ from django.db.backends.utils import truncate_name
class DatabaseCreation(BaseDatabaseCreation):
- # This dictionary maps Field objects to their associated PostgreSQL column
- # types, as strings. Column-type strings can contain format strings; they'll
- # be interpolated against the values of Field.__dict__ before being output.
- # If a column type is set to None, it won't be included in the output.
- data_types = {
- 'AutoField': 'serial',
- 'BinaryField': 'bytea',
- 'BooleanField': 'boolean',
- 'CharField': 'varchar(%(max_length)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
- 'DateField': 'date',
- 'DateTimeField': 'timestamp with time zone',
- 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'DurationField': 'interval',
- 'FileField': 'varchar(%(max_length)s)',
- 'FilePathField': 'varchar(%(max_length)s)',
- 'FloatField': 'double precision',
- 'IntegerField': 'integer',
- 'BigIntegerField': 'bigint',
- 'IPAddressField': 'inet',
- 'GenericIPAddressField': 'inet',
- 'NullBooleanField': 'boolean',
- 'OneToOneField': 'integer',
- 'PositiveIntegerField': 'integer',
- 'PositiveSmallIntegerField': 'smallint',
- 'SlugField': 'varchar(%(max_length)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'text',
- 'TimeField': 'time',
- 'UUIDField': 'uuid',
- }
-
- data_type_check_constraints = {
- 'PositiveIntegerField': '"%(column)s" >= 0',
- 'PositiveSmallIntegerField': '"%(column)s" >= 0',
- }
def sql_table_creation_suffix(self):
test_settings = self.connection.settings_dict['TEST']
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index 3560d4498e..4e0cf0c9aa 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -336,6 +336,39 @@ class DatabaseOperations(BaseDatabaseOperations):
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'sqlite'
+ # SQLite doesn't actually support most of these types, but it "does the right
+ # thing" given more verbose field definitions, so leave them as is so that
+ # schema inspection is more useful.
+ data_types = {
+ 'AutoField': 'integer',
+ 'BinaryField': 'BLOB',
+ 'BooleanField': 'bool',
+ 'CharField': 'varchar(%(max_length)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
+ 'DateField': 'date',
+ 'DateTimeField': 'datetime',
+ 'DecimalField': 'decimal',
+ 'DurationField': 'bigint',
+ 'FileField': 'varchar(%(max_length)s)',
+ 'FilePathField': 'varchar(%(max_length)s)',
+ 'FloatField': 'real',
+ 'IntegerField': 'integer',
+ 'BigIntegerField': 'bigint',
+ 'IPAddressField': 'char(15)',
+ 'GenericIPAddressField': 'char(39)',
+ 'NullBooleanField': 'bool',
+ 'OneToOneField': 'integer',
+ 'PositiveIntegerField': 'integer unsigned',
+ 'PositiveSmallIntegerField': 'smallint unsigned',
+ 'SlugField': 'varchar(%(max_length)s)',
+ 'SmallIntegerField': 'smallint',
+ 'TextField': 'text',
+ 'TimeField': 'time',
+ 'UUIDField': 'char(32)',
+ }
+ data_types_suffix = {
+ 'AutoField': 'AUTOINCREMENT',
+ }
# SQLite requires LIKE statements to include an ESCAPE clause if the value
# being escaped has a percent or underscore in it.
# See http://www.sqlite.org/lang_expr.html for an explanation.
diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py
index ad7822c718..3f1372630a 100644
--- a/django/db/backends/sqlite3/creation.py
+++ b/django/db/backends/sqlite3/creation.py
@@ -7,39 +7,6 @@ from django.utils.six.moves import input
class DatabaseCreation(BaseDatabaseCreation):
- # SQLite doesn't actually support most of these types, but it "does the right
- # thing" given more verbose field definitions, so leave them as is so that
- # schema inspection is more useful.
- data_types = {
- 'AutoField': 'integer',
- 'BinaryField': 'BLOB',
- 'BooleanField': 'bool',
- 'CharField': 'varchar(%(max_length)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
- 'DateField': 'date',
- 'DateTimeField': 'datetime',
- 'DecimalField': 'decimal',
- 'DurationField': 'bigint',
- 'FileField': 'varchar(%(max_length)s)',
- 'FilePathField': 'varchar(%(max_length)s)',
- 'FloatField': 'real',
- 'IntegerField': 'integer',
- 'BigIntegerField': 'bigint',
- 'IPAddressField': 'char(15)',
- 'GenericIPAddressField': 'char(39)',
- 'NullBooleanField': 'bool',
- 'OneToOneField': 'integer',
- 'PositiveIntegerField': 'integer unsigned',
- 'PositiveSmallIntegerField': 'smallint unsigned',
- 'SlugField': 'varchar(%(max_length)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'text',
- 'TimeField': 'time',
- 'UUIDField': 'char(32)',
- }
- data_types_suffix = {
- 'AutoField': 'AUTOINCREMENT',
- }
def sql_for_pending_references(self, model, style, pending_references):
"SQLite3 doesn't support constraints"
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 0a87f7812c..bc7bbc1a30 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -537,7 +537,7 @@ class Field(RegisterLookupMixin):
# exactly which wacky database column type you want to use.
data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
try:
- return connection.creation.data_types[self.get_internal_type()] % data
+ return connection.data_types[self.get_internal_type()] % data
except KeyError:
return None
@@ -550,7 +550,7 @@ class Field(RegisterLookupMixin):
data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
type_string = self.db_type(connection)
try:
- check_string = connection.creation.data_type_check_constraints[self.get_internal_type()] % data
+ check_string = connection.data_type_check_constraints[self.get_internal_type()] % data
except KeyError:
check_string = None
return {
@@ -559,7 +559,7 @@ class Field(RegisterLookupMixin):
}
def db_type_suffix(self, connection):
- return connection.creation.data_types_suffix.get(self.get_internal_type())
+ return connection.data_types_suffix.get(self.get_internal_type())
def get_db_converters(self, connection):
if hasattr(self, 'from_db_value'):
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index a34f3bf5b8..f1e8eceee6 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -849,6 +849,16 @@ Also private APIs ``django.template.base.compile_string()``,
``django.template.loader.find_template()``, and
``django.template.loader.get_template_from_string()`` were removed.
+Database backend API
+~~~~~~~~~~~~~~~~~~~~
+
+The following changes to the database backend API are documented to assist
+those writing third-party backends in updating their code:
+
+* The ``data_types``, ``data_types_suffix``, and
+ ``data_type_check_constraints`` attributes have moved from the
+ ``DatabaseCreation`` class to ``DatabaseWrapper``.
+
Miscellaneous
~~~~~~~~~~~~~
diff --git a/tests/commands_sql/tests.py b/tests/commands_sql/tests.py
index 83c47a888f..5eb9f0191a 100644
--- a/tests/commands_sql/tests.py
+++ b/tests/commands_sql/tests.py
@@ -45,7 +45,7 @@ class SQLCommandsTestCase(TestCase):
'commands_sql_comment', 'commands_sql_book', 'commands_sql_book_comments'
})
- @unittest.skipUnless('PositiveIntegerField' in connections[DEFAULT_DB_ALIAS].creation.data_type_check_constraints, 'Backend does not have checks.')
+ @unittest.skipUnless('PositiveIntegerField' in connections[DEFAULT_DB_ALIAS].data_type_check_constraints, 'Backend does not have checks.')
def test_sql_create_check(self):
"""Regression test for #23416 -- Check that db_params['check'] is respected."""
app_config = apps.get_app_config('commands_sql')