1
0
mirror of https://github.com/django/django.git synced 2025-08-10 20:09:12 +00:00

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 the backend introspect an BinaryField, instead of an TextField?
can_introspect_binary_field = True can_introspect_binary_field = True
# Can the backend introspect an BooleanField, instead of an IntegerField? # What is the type returned when the backend introspect a BooleanField?
can_introspect_boolean_field = True introspected_boolean_field_type = 'BooleanField'
# Can the backend introspect an DecimalField, instead of an FloatField? # Can the backend introspect an DecimalField, instead of an FloatField?
can_introspect_decimal_field = True can_introspect_decimal_field = True

View File

@ -178,7 +178,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_regex_backreferencing = False supports_regex_backreferencing = False
supports_date_lookup_using_string = False supports_date_lookup_using_string = False
can_introspect_binary_field = False can_introspect_binary_field = False
can_introspect_boolean_field = False introspected_boolean_field_type = 'IntegerField'
can_introspect_small_integer_field = True can_introspect_small_integer_field = True
supports_timezones = False supports_timezones = False
requires_explicit_null_ordering_when_grouping = True 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. # select for update with limit can be achieved on Oracle, but not with the current backend.
supports_select_for_update_with_limit = False 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): class DatabaseOperations(BaseDatabaseOperations):
compiler_module = "django.db.backends.oracle.compiler" compiler_module = "django.db.backends.oracle.compiler"
@ -735,20 +749,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
except ValueError: except ValueError:
return None 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): class OracleParam(object):
""" """

View File

@ -87,18 +87,19 @@ class InspectDBTestCase(TestCase):
else: else:
assertFieldType('big_int_field', "models.IntegerField()") 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()") assertFieldType('bool_field', "models.BooleanField()")
if connection.features.can_introspect_null: if connection.features.can_introspect_null:
assertFieldType('null_bool_field', "models.NullBooleanField()") assertFieldType('null_bool_field', "models.NullBooleanField()")
else: else:
assertFieldType('null_bool_field', "models.BooleanField()") assertFieldType('null_bool_field', "models.BooleanField()")
else: 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: 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: else:
assertFieldType('null_bool_field', "models.IntegerField()") assertFieldType('null_bool_field', "models.{}()".format(field_type))
if connection.features.can_introspect_decimal_field: if connection.features.can_introspect_decimal_field:
assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)") 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 # Ensure the field is right afterwards
columns = self.column_classes(Author) columns = self.column_classes(Author)
# BooleanField are stored as TINYINT(1) on MySQL. # BooleanField are stored as TINYINT(1) on MySQL.
field_type, field_info = columns['awesome'] field_type = columns['awesome'][0]
if connection.vendor == 'mysql': self.assertEqual(field_type, connection.features.introspected_boolean_field_type)
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')
def test_add_field_default_transform(self): def test_add_field_default_transform(self):
""" """