Loading django/db/backends/__init__.py +17 −3 Original line number Diff line number Diff line Loading @@ -614,9 +614,6 @@ class BaseDatabaseFeatures(object): # Can the backend introspect an BinaryField, instead of an TextField? can_introspect_binary_field = True # What is the type returned when the backend introspect a BooleanField? introspected_boolean_field_type = 'BooleanField' # Can the backend introspect an DecimalField, instead of an FloatField? can_introspect_decimal_field = True Loading Loading @@ -715,6 +712,23 @@ class BaseDatabaseFeatures(object): except NotImplementedError: return False def introspected_boolean_field_type(self, field=None, created_separately=False): """ What is the type returned when the backend introspects a BooleanField? The optional arguments may be used to give further details of the field to be introspected; in particular, they are provided by Django's test suite: field -- the field definition created_separately -- True if the field was added via a SchemaEditor's AddField, False if the field was created with the model Note that return value from this function is compared by tests against actual introspection results; it should provide expectations, not run an introspection itself. """ if self.can_introspect_null and field and field.null: return 'NullBooleanField' return 'BooleanField' class BaseDatabaseOperations(object): """ Loading django/db/backends/mysql/base.py +3 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_regex_backreferencing = False supports_date_lookup_using_string = False can_introspect_binary_field = False introspected_boolean_field_type = 'IntegerField' can_introspect_small_integer_field = True supports_timezones = False requires_explicit_null_ordering_when_grouping = True Loading Loading @@ -225,6 +224,9 @@ class DatabaseFeatures(BaseDatabaseFeatures): cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1") return cursor.fetchone() is not None def introspected_boolean_field_type(self, *args): return 'IntegerField' class DatabaseOperations(BaseDatabaseOperations): compiler_module = "django.db.backends.mysql.compiler" Loading django/db/backends/oracle/base.py +8 −7 Original line number Diff line number Diff line Loading @@ -125,19 +125,20 @@ class DatabaseFeatures(BaseDatabaseFeatures): # select for update with limit can be achieved on Oracle, but not with the current backend. supports_select_for_update_with_limit = False @cached_property def introspected_boolean_field_type(self): def introspected_boolean_field_type(self, field=None, created_separately=False): """ Some versions of Oracle -- we've seen this on 11.2.0.1 and suspect it goes back -- have a weird bug where, when an integer column is defined with a default, its precision is later reported on introspection as 0, regardless of the real precision. For Django introspection, this means that such columns are reported as IntegerField even if they are really BigIntegerField or BooleanField. added to an existing table with a default, its precision is later reported on introspection as 0, regardless of the real precision. For Django introspection, this means that such columns are reported as IntegerField even if they are really BigIntegerField or BooleanField. The bug is solved in Oracle 11.2.0.2 and up. """ return 'IntegerField' if self.connection.oracle_full_version < '11.2.0.2' else 'BooleanField' if self.connection.oracle_full_version < '11.2.0.2' and field and field.has_default() and created_separately: return 'IntegerField' return super(DatabaseFeatures, self).introspected_boolean_field_type(field, created_separately) class DatabaseOperations(BaseDatabaseOperations): Loading tests/inspectdb/tests.py +11 −10 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ from django.db import connection from django.test import TestCase, skipUnlessDBFeature from django.utils.six import PY3, StringIO from .models import ColumnTypes class InspectDBTestCase(TestCase): Loading Loading @@ -87,19 +89,18 @@ class InspectDBTestCase(TestCase): else: assertFieldType('big_int_field', "models.IntegerField()") if connection.features.introspected_boolean_field_type == 'BooleanField': assertFieldType('bool_field', "models.BooleanField()") if connection.features.can_introspect_null: assertFieldType('null_bool_field', "models.NullBooleanField()") else: assertFieldType('null_bool_field', "models.BooleanField()") bool_field = ColumnTypes._meta.get_field('bool_field') bool_field_type = connection.features.introspected_boolean_field_type(bool_field) assertFieldType('bool_field', "models.{}()".format(bool_field_type)) null_bool_field = ColumnTypes._meta.get_field('null_bool_field') null_bool_field_type = connection.features.introspected_boolean_field_type(null_bool_field) if 'BooleanField' in null_bool_field_type: assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type)) else: field_type = connection.features.introspected_boolean_field_type assertFieldType('bool_field', "models.{}()".format(field_type)) if connection.features.can_introspect_null: assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(field_type)) assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(null_bool_field_type)) else: assertFieldType('null_bool_field', "models.{}()".format(field_type)) assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type)) if connection.features.can_introspect_decimal_field: assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)") Loading tests/schema/tests.py +1 −1 Original line number Diff line number Diff line Loading @@ -314,7 +314,7 @@ class SchemaTests(TransactionTestCase): columns = self.column_classes(Author) # BooleanField are stored as TINYINT(1) on MySQL. field_type = columns['awesome'][0] self.assertEqual(field_type, connection.features.introspected_boolean_field_type) self.assertEqual(field_type, connection.features.introspected_boolean_field_type(new_field, created_separately=True)) def test_add_field_default_transform(self): """ Loading Loading
django/db/backends/__init__.py +17 −3 Original line number Diff line number Diff line Loading @@ -614,9 +614,6 @@ class BaseDatabaseFeatures(object): # Can the backend introspect an BinaryField, instead of an TextField? can_introspect_binary_field = True # What is the type returned when the backend introspect a BooleanField? introspected_boolean_field_type = 'BooleanField' # Can the backend introspect an DecimalField, instead of an FloatField? can_introspect_decimal_field = True Loading Loading @@ -715,6 +712,23 @@ class BaseDatabaseFeatures(object): except NotImplementedError: return False def introspected_boolean_field_type(self, field=None, created_separately=False): """ What is the type returned when the backend introspects a BooleanField? The optional arguments may be used to give further details of the field to be introspected; in particular, they are provided by Django's test suite: field -- the field definition created_separately -- True if the field was added via a SchemaEditor's AddField, False if the field was created with the model Note that return value from this function is compared by tests against actual introspection results; it should provide expectations, not run an introspection itself. """ if self.can_introspect_null and field and field.null: return 'NullBooleanField' return 'BooleanField' class BaseDatabaseOperations(object): """ Loading
django/db/backends/mysql/base.py +3 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_regex_backreferencing = False supports_date_lookup_using_string = False can_introspect_binary_field = False introspected_boolean_field_type = 'IntegerField' can_introspect_small_integer_field = True supports_timezones = False requires_explicit_null_ordering_when_grouping = True Loading Loading @@ -225,6 +224,9 @@ class DatabaseFeatures(BaseDatabaseFeatures): cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1") return cursor.fetchone() is not None def introspected_boolean_field_type(self, *args): return 'IntegerField' class DatabaseOperations(BaseDatabaseOperations): compiler_module = "django.db.backends.mysql.compiler" Loading
django/db/backends/oracle/base.py +8 −7 Original line number Diff line number Diff line Loading @@ -125,19 +125,20 @@ class DatabaseFeatures(BaseDatabaseFeatures): # select for update with limit can be achieved on Oracle, but not with the current backend. supports_select_for_update_with_limit = False @cached_property def introspected_boolean_field_type(self): def introspected_boolean_field_type(self, field=None, created_separately=False): """ Some versions of Oracle -- we've seen this on 11.2.0.1 and suspect it goes back -- have a weird bug where, when an integer column is defined with a default, its precision is later reported on introspection as 0, regardless of the real precision. For Django introspection, this means that such columns are reported as IntegerField even if they are really BigIntegerField or BooleanField. added to an existing table with a default, its precision is later reported on introspection as 0, regardless of the real precision. For Django introspection, this means that such columns are reported as IntegerField even if they are really BigIntegerField or BooleanField. The bug is solved in Oracle 11.2.0.2 and up. """ return 'IntegerField' if self.connection.oracle_full_version < '11.2.0.2' else 'BooleanField' if self.connection.oracle_full_version < '11.2.0.2' and field and field.has_default() and created_separately: return 'IntegerField' return super(DatabaseFeatures, self).introspected_boolean_field_type(field, created_separately) class DatabaseOperations(BaseDatabaseOperations): Loading
tests/inspectdb/tests.py +11 −10 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ from django.db import connection from django.test import TestCase, skipUnlessDBFeature from django.utils.six import PY3, StringIO from .models import ColumnTypes class InspectDBTestCase(TestCase): Loading Loading @@ -87,19 +89,18 @@ class InspectDBTestCase(TestCase): else: assertFieldType('big_int_field', "models.IntegerField()") if connection.features.introspected_boolean_field_type == 'BooleanField': assertFieldType('bool_field', "models.BooleanField()") if connection.features.can_introspect_null: assertFieldType('null_bool_field', "models.NullBooleanField()") else: assertFieldType('null_bool_field', "models.BooleanField()") bool_field = ColumnTypes._meta.get_field('bool_field') bool_field_type = connection.features.introspected_boolean_field_type(bool_field) assertFieldType('bool_field', "models.{}()".format(bool_field_type)) null_bool_field = ColumnTypes._meta.get_field('null_bool_field') null_bool_field_type = connection.features.introspected_boolean_field_type(null_bool_field) if 'BooleanField' in null_bool_field_type: assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type)) else: field_type = connection.features.introspected_boolean_field_type assertFieldType('bool_field', "models.{}()".format(field_type)) if connection.features.can_introspect_null: assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(field_type)) assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(null_bool_field_type)) else: assertFieldType('null_bool_field', "models.{}()".format(field_type)) assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type)) if connection.features.can_introspect_decimal_field: assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)") Loading
tests/schema/tests.py +1 −1 Original line number Diff line number Diff line Loading @@ -314,7 +314,7 @@ class SchemaTests(TransactionTestCase): columns = self.column_classes(Author) # BooleanField are stored as TINYINT(1) on MySQL. field_type = columns['awesome'][0] self.assertEqual(field_type, connection.features.introspected_boolean_field_type) self.assertEqual(field_type, connection.features.introspected_boolean_field_type(new_field, created_separately=True)) def test_add_field_default_transform(self): """ Loading