Fixed #31630 -- Replaced introspection features with DatabaseFeatures.introspected_field_types.
This commit is contained in:
parent
55556e51fb
commit
e198beadad
|
@ -128,38 +128,22 @@ class BaseDatabaseFeatures:
|
|||
# Can the backend introspect an AutoField, instead of an IntegerField?
|
||||
can_introspect_autofield = False
|
||||
|
||||
# Can the backend introspect a BigIntegerField, instead of an IntegerField?
|
||||
can_introspect_big_integer_field = True
|
||||
|
||||
# Can the backend introspect an BinaryField, instead of an TextField?
|
||||
can_introspect_binary_field = True
|
||||
|
||||
# Can the backend introspect an DecimalField, instead of an FloatField?
|
||||
can_introspect_decimal_field = True
|
||||
|
||||
# Can the backend introspect a DurationField, instead of a BigIntegerField?
|
||||
can_introspect_duration_field = True
|
||||
|
||||
# Can the backend introspect an IPAddressField, instead of an CharField?
|
||||
can_introspect_ip_address_field = False
|
||||
|
||||
# Can the backend introspect a PositiveIntegerField, instead of an IntegerField?
|
||||
can_introspect_positive_integer_field = False
|
||||
|
||||
# Can the backend introspect a SmallIntegerField, instead of an IntegerField?
|
||||
can_introspect_small_integer_field = False
|
||||
|
||||
# Can the backend introspect a TimeField, instead of a DateTimeField?
|
||||
can_introspect_time_field = True
|
||||
|
||||
# Some backends may not be able to differentiate BigAutoField or
|
||||
# SmallAutoField from other fields such as AutoField.
|
||||
introspected_big_auto_field_type = 'BigAutoField'
|
||||
introspected_small_auto_field_type = 'SmallAutoField'
|
||||
|
||||
# Some backends may not be able to differentiate BooleanField from other
|
||||
# fields such as IntegerField.
|
||||
introspected_boolean_field_type = 'BooleanField'
|
||||
# Map fields which some backends may not be able to differentiate to the
|
||||
# field it's introspected as.
|
||||
introspected_field_types = {
|
||||
'BigAutoField': 'BigAutoField',
|
||||
'BigIntegerField': 'BigIntegerField',
|
||||
'BinaryField': 'BinaryField',
|
||||
'BooleanField': 'BooleanField',
|
||||
'DurationField': 'DurationField',
|
||||
'GenericIPAddressField': 'GenericIPAddressField',
|
||||
'PositiveBigIntegerField': 'PositiveBigIntegerField',
|
||||
'PositiveIntegerField': 'PositiveIntegerField',
|
||||
'PositiveSmallIntegerField': 'PositiveSmallIntegerField',
|
||||
'SmallAutoField': 'SmallAutoField',
|
||||
'SmallIntegerField': 'SmallIntegerField',
|
||||
'TimeField': 'TimeField',
|
||||
}
|
||||
|
||||
# Can the backend introspect the column order (ASC/DESC) for indexes?
|
||||
supports_index_column_ordering = True
|
||||
|
|
|
@ -15,11 +15,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
supports_regex_backreferencing = False
|
||||
supports_date_lookup_using_string = False
|
||||
can_introspect_autofield = True
|
||||
can_introspect_binary_field = False
|
||||
can_introspect_duration_field = False
|
||||
can_introspect_small_integer_field = True
|
||||
can_introspect_positive_integer_field = True
|
||||
introspected_boolean_field_type = 'IntegerField'
|
||||
supports_index_column_ordering = False
|
||||
supports_timezones = False
|
||||
requires_explicit_null_ordering_when_grouping = True
|
||||
|
@ -70,6 +65,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
"Confirm support for introspected foreign keys"
|
||||
return self._mysql_storage_engine != 'MyISAM'
|
||||
|
||||
@cached_property
|
||||
def introspected_field_types(self):
|
||||
return {
|
||||
**super().introspected_field_types,
|
||||
'BinaryField': 'TextField',
|
||||
'BooleanField': 'IntegerField',
|
||||
'DurationField': 'BigIntegerField',
|
||||
'GenericIPAddressField': 'CharField',
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def can_return_columns_from_insert(self):
|
||||
return self.connection.mysql_is_mariadb and self.connection.mysql_version >= (10, 5, 0)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import InterfaceError
|
||||
from django.db.backends.base.features import BaseDatabaseFeatures
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
|
||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
|
@ -22,7 +23,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
supports_tablespaces = True
|
||||
supports_sequence_reset = False
|
||||
can_introspect_materialized_views = True
|
||||
can_introspect_time_field = False
|
||||
atomic_transactions = False
|
||||
supports_combined_alters = False
|
||||
nulls_order_largest = True
|
||||
|
@ -61,3 +61,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
allows_multiple_constraints_on_same_fields = False
|
||||
supports_boolean_expr_in_select_clause = False
|
||||
supports_primitives_in_json_field = False
|
||||
|
||||
@cached_property
|
||||
def introspected_field_types(self):
|
||||
return {
|
||||
**super().introspected_field_types,
|
||||
'GenericIPAddressField': 'CharField',
|
||||
'PositiveBigIntegerField': 'BigIntegerField',
|
||||
'PositiveIntegerField': 'IntegerField',
|
||||
'PositiveSmallIntegerField': 'IntegerField',
|
||||
'SmallIntegerField': 'IntegerField',
|
||||
'TimeField': 'DateTimeField',
|
||||
}
|
||||
|
|
|
@ -22,10 +22,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
can_release_savepoints = True
|
||||
supports_tablespaces = True
|
||||
supports_transactions = True
|
||||
can_introspect_autofield = True
|
||||
can_introspect_ip_address_field = True
|
||||
can_introspect_materialized_views = True
|
||||
can_introspect_small_integer_field = True
|
||||
can_distinct_on_fields = True
|
||||
can_rollback_ddl = True
|
||||
supports_combined_alters = True
|
||||
|
@ -61,6 +58,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
supports_deferrable_unique_constraints = True
|
||||
has_json_operators = True
|
||||
|
||||
@cached_property
|
||||
def introspected_field_types(self):
|
||||
return {
|
||||
**super().introspected_field_types,
|
||||
'PositiveBigIntegerField': 'BigIntegerField',
|
||||
'PositiveIntegerField': 'IntegerField',
|
||||
'PositiveSmallIntegerField': 'SmallIntegerField',
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def is_postgresql_10(self):
|
||||
return self.connection.pg_version >= 100000
|
||||
|
|
|
@ -19,12 +19,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
max_query_params = 999
|
||||
supports_mixed_date_datetime_comparisons = False
|
||||
can_introspect_autofield = True
|
||||
can_introspect_decimal_field = False
|
||||
can_introspect_duration_field = False
|
||||
can_introspect_positive_integer_field = True
|
||||
can_introspect_small_integer_field = True
|
||||
introspected_big_auto_field_type = 'AutoField'
|
||||
introspected_small_auto_field_type = 'AutoField'
|
||||
supports_transactions = True
|
||||
atomic_transactions = False
|
||||
can_rollback_ddl = True
|
||||
|
@ -51,6 +45,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||
supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
|
||||
order_by_nulls_first = True
|
||||
|
||||
@cached_property
|
||||
def introspected_field_types(self):
|
||||
return{
|
||||
**super().introspected_field_types,
|
||||
'BigAutoField': 'AutoField',
|
||||
'DurationField': 'BigIntegerField',
|
||||
'GenericIPAddressField': 'CharField',
|
||||
'SmallAutoField': 'AutoField',
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def supports_json_field(self):
|
||||
try:
|
||||
|
|
|
@ -247,7 +247,20 @@ Database backend API
|
|||
This section describes changes that may be needed in third-party database
|
||||
backends.
|
||||
|
||||
* ...
|
||||
* The new ``DatabaseFeatures.introspected_field_types`` property replaces these
|
||||
features:
|
||||
|
||||
* ``can_introspect_big_integer_field``
|
||||
* ``can_introspect_binary_field``
|
||||
* ``can_introspect_decimal_field``
|
||||
* ``can_introspect_duration_field``
|
||||
* ``can_introspect_ip_address_field``
|
||||
* ``can_introspect_positive_integer_field``
|
||||
* ``can_introspect_small_integer_field``
|
||||
* ``can_introspect_time_field``
|
||||
* ``introspected_big_auto_field_type``
|
||||
* ``introspected_small_auto_field_type``
|
||||
* ``introspected_boolean_field_type``
|
||||
|
||||
:mod:`django.contrib.gis`
|
||||
-------------------------
|
||||
|
|
|
@ -60,6 +60,7 @@ class InspectDBTestCase(TestCase):
|
|||
def test_field_types(self):
|
||||
"""Test introspection of various Django field types"""
|
||||
assertFieldType = self.make_field_type_asserter()
|
||||
introspected_field_types = connection.features.introspected_field_types
|
||||
|
||||
# Inspecting Oracle DB doesn't produce correct results (#19884):
|
||||
# - it reports fields as blank=True when they aren't.
|
||||
|
@ -74,12 +75,11 @@ class InspectDBTestCase(TestCase):
|
|||
assertFieldType('url_field', "models.CharField(max_length=200)")
|
||||
assertFieldType('date_field', "models.DateField()")
|
||||
assertFieldType('date_time_field', "models.DateTimeField()")
|
||||
if connection.features.can_introspect_ip_address_field:
|
||||
if introspected_field_types['GenericIPAddressField'] == 'GenericIPAddressField':
|
||||
assertFieldType('gen_ip_address_field', "models.GenericIPAddressField()")
|
||||
elif not connection.features.interprets_empty_strings_as_nulls:
|
||||
assertFieldType('gen_ip_address_field', "models.CharField(max_length=39)")
|
||||
if connection.features.can_introspect_time_field:
|
||||
assertFieldType('time_field', "models.TimeField()")
|
||||
assertFieldType('time_field', 'models.%s()' % introspected_field_types['TimeField'])
|
||||
if connection.features.has_native_uuid_field:
|
||||
assertFieldType('uuid_field', "models.UUIDField()")
|
||||
elif not connection.features.interprets_empty_strings_as_nulls:
|
||||
|
@ -97,20 +97,18 @@ class InspectDBTestCase(TestCase):
|
|||
def test_number_field_types(self):
|
||||
"""Test introspection of various Django field types"""
|
||||
assertFieldType = self.make_field_type_asserter()
|
||||
introspected_field_types = connection.features.introspected_field_types
|
||||
|
||||
if not connection.features.can_introspect_autofield:
|
||||
assertFieldType('id', "models.IntegerField(primary_key=True) # AutoField?")
|
||||
|
||||
if connection.features.can_introspect_big_integer_field:
|
||||
assertFieldType('big_int_field', "models.BigIntegerField()")
|
||||
else:
|
||||
assertFieldType('big_int_field', "models.IntegerField()")
|
||||
assertFieldType('big_int_field', 'models.%s()' % introspected_field_types['BigIntegerField'])
|
||||
|
||||
bool_field_type = connection.features.introspected_boolean_field_type
|
||||
bool_field_type = introspected_field_types['BooleanField']
|
||||
assertFieldType('bool_field', "models.{}()".format(bool_field_type))
|
||||
assertFieldType('null_bool_field', 'models.{}(blank=True, null=True)'.format(bool_field_type))
|
||||
|
||||
if connection.features.can_introspect_decimal_field:
|
||||
if connection.vendor != 'sqlite':
|
||||
assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")
|
||||
else: # Guessed arguments on SQLite, see #5014
|
||||
assertFieldType('decimal_field', "models.DecimalField(max_digits=10, decimal_places=5) "
|
||||
|
@ -118,37 +116,11 @@ class InspectDBTestCase(TestCase):
|
|||
"as this database handles decimal fields as float")
|
||||
|
||||
assertFieldType('float_field', "models.FloatField()")
|
||||
|
||||
assertFieldType('int_field', "models.IntegerField()")
|
||||
|
||||
if connection.features.can_introspect_positive_integer_field:
|
||||
assertFieldType('pos_int_field', "models.PositiveIntegerField()")
|
||||
else:
|
||||
assertFieldType('pos_int_field', "models.IntegerField()")
|
||||
|
||||
if connection.features.can_introspect_positive_integer_field:
|
||||
if connection.features.can_introspect_big_integer_field:
|
||||
assertFieldType('pos_big_int_field', 'models.PositiveBigIntegerField()')
|
||||
else:
|
||||
assertFieldType('pos_big_int_field', 'models.PositiveIntegerField()')
|
||||
if connection.features.can_introspect_small_integer_field:
|
||||
assertFieldType('pos_small_int_field', "models.PositiveSmallIntegerField()")
|
||||
else:
|
||||
assertFieldType('pos_small_int_field', "models.PositiveIntegerField()")
|
||||
else:
|
||||
if connection.features.can_introspect_big_integer_field:
|
||||
assertFieldType('pos_big_int_field', 'models.BigIntegerField()')
|
||||
else:
|
||||
assertFieldType('pos_big_int_field', 'models.IntegerField()')
|
||||
if connection.features.can_introspect_small_integer_field:
|
||||
assertFieldType('pos_small_int_field', "models.SmallIntegerField()")
|
||||
else:
|
||||
assertFieldType('pos_small_int_field', "models.IntegerField()")
|
||||
|
||||
if connection.features.can_introspect_small_integer_field:
|
||||
assertFieldType('small_int_field', "models.SmallIntegerField()")
|
||||
else:
|
||||
assertFieldType('small_int_field', "models.IntegerField()")
|
||||
assertFieldType('pos_int_field', 'models.%s()' % introspected_field_types['PositiveIntegerField'])
|
||||
assertFieldType('pos_big_int_field', 'models.%s()' % introspected_field_types['PositiveBigIntegerField'])
|
||||
assertFieldType('pos_small_int_field', 'models.%s()' % introspected_field_types['PositiveSmallIntegerField'])
|
||||
assertFieldType('small_int_field', 'models.%s()' % introspected_field_types['SmallIntegerField'])
|
||||
|
||||
@skipUnlessDBFeature('can_introspect_foreign_keys')
|
||||
def test_attribute_name_not_python_keyword(self):
|
||||
|
|
|
@ -84,10 +84,10 @@ class IntrospectionTests(TransactionTestCase):
|
|||
'CharField',
|
||||
'CharField',
|
||||
'CharField',
|
||||
'BigIntegerField' if connection.features.can_introspect_big_integer_field else 'IntegerField',
|
||||
'BinaryField' if connection.features.can_introspect_binary_field else 'TextField',
|
||||
'SmallIntegerField' if connection.features.can_introspect_small_integer_field else 'IntegerField',
|
||||
'DurationField' if connection.features.can_introspect_duration_field else 'BigIntegerField',
|
||||
connection.features.introspected_field_types['BigIntegerField'],
|
||||
connection.features.introspected_field_types['BinaryField'],
|
||||
connection.features.introspected_field_types['SmallIntegerField'],
|
||||
connection.features.introspected_field_types['DurationField'],
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -113,7 +113,7 @@ class IntrospectionTests(TransactionTestCase):
|
|||
with connection.cursor() as cursor:
|
||||
desc = connection.introspection.get_table_description(cursor, City._meta.db_table)
|
||||
self.assertIn(
|
||||
connection.features.introspected_big_auto_field_type,
|
||||
connection.features.introspected_field_types['BigAutoField'],
|
||||
[connection.introspection.get_field_type(r[1], r) for r in desc],
|
||||
)
|
||||
|
||||
|
@ -122,7 +122,7 @@ class IntrospectionTests(TransactionTestCase):
|
|||
with connection.cursor() as cursor:
|
||||
desc = connection.introspection.get_table_description(cursor, Country._meta.db_table)
|
||||
self.assertIn(
|
||||
connection.features.introspected_small_auto_field_type,
|
||||
connection.features.introspected_field_types['SmallAutoField'],
|
||||
[connection.introspection.get_field_type(r[1], r) for r in desc],
|
||||
)
|
||||
|
||||
|
|
|
@ -559,7 +559,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_field_types['BooleanField'])
|
||||
|
||||
def test_add_field_default_transform(self):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue