Fixed #22738 -- Abstracted boolean field type introspection

Thanks maxi for the report, Shai Berger for his help with the patch
and Tim Graham for the review.
This commit is contained in:
Claude Paroz 2014-09-26 08:43:50 +02:00
parent 45840927d3
commit dbdae3a755
5 changed files with 24 additions and 30 deletions

View File

@ -614,8 +614,8 @@ class BaseDatabaseFeatures(object):
# Can the backend introspect an BinaryField, instead of an TextField?
can_introspect_binary_field = True
# Can the backend introspect an BooleanField, instead of an IntegerField?
can_introspect_boolean_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

View File

@ -178,7 +178,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_regex_backreferencing = False
supports_date_lookup_using_string = False
can_introspect_binary_field = False
can_introspect_boolean_field = False
introspected_boolean_field_type = 'IntegerField'
can_introspect_small_integer_field = True
supports_timezones = False
requires_explicit_null_ordering_when_grouping = True

View File

@ -125,6 +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):
"""
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.
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'
class DatabaseOperations(BaseDatabaseOperations):
compiler_module = "django.db.backends.oracle.compiler"
@ -735,20 +749,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
except ValueError:
return None
@cached_property
def version_has_default_introspection_bug(self):
"""
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.
The bug is solved in Oracle 11.2.0.2 and up.
"""
return self.oracle_full_version < '11.2.0.2'
class OracleParam(object):
"""

View File

@ -87,18 +87,19 @@ class InspectDBTestCase(TestCase):
else:
assertFieldType('big_int_field', "models.IntegerField()")
if connection.features.can_introspect_boolean_field:
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()")
else:
assertFieldType('bool_field', "models.IntegerField()")
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.IntegerField(blank=True, null=True)")
assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(field_type))
else:
assertFieldType('null_bool_field', "models.IntegerField()")
assertFieldType('null_bool_field', "models.{}()".format(field_type))
if connection.features.can_introspect_decimal_field:
assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")

View File

@ -313,15 +313,8 @@ class SchemaTests(TransactionTestCase):
# Ensure the field is right afterwards
columns = self.column_classes(Author)
# BooleanField are stored as TINYINT(1) on MySQL.
field_type, field_info = columns['awesome']
if connection.vendor == 'mysql':
self.assertEqual(field_type, 'IntegerField')
self.assertEqual(field_info.precision, 1)
elif connection.vendor == 'oracle' and connection.version_has_default_introspection_bug:
self.assertEqual(field_type, 'IntegerField')
self.assertEqual(field_info.precision, 0)
else:
self.assertEqual(field_type, 'BooleanField')
field_type = columns['awesome'][0]
self.assertEqual(field_type, connection.features.introspected_boolean_field_type)
def test_add_field_default_transform(self):
"""