summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHasan Ramezani <hasan.r67@gmail.com>2020-05-27 00:25:45 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-06-04 08:27:42 +0200
commite198beadad56d5fdd06756b097446b7046a84010 (patch)
tree259d188fe8ab2490916419a771163a750b618935
parent55556e51fb152c864ddc782d9b56e8b785ccf8bc (diff)
Fixed #31630 -- Replaced introspection features with DatabaseFeatures.introspected_field_types.
-rw-r--r--django/db/backends/base/features.py48
-rw-r--r--django/db/backends/mysql/features.py15
-rw-r--r--django/db/backends/oracle/features.py14
-rw-r--r--django/db/backends/postgresql/features.py12
-rw-r--r--django/db/backends/sqlite3/features.py16
-rw-r--r--docs/releases/3.2.txt15
-rw-r--r--tests/inspectdb/tests.py50
-rw-r--r--tests/introspection/tests.py12
-rw-r--r--tests/schema/tests.py2
9 files changed, 90 insertions, 94 deletions
diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index 31113e1c7a..533dbc7fec 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -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
diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py
index 499c303d9e..a1a6e4b084 100644
--- a/django/db/backends/mysql/features.py
+++ b/django/db/backends/mysql/features.py
@@ -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
@@ -71,6 +66,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
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)
diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py
index bae09559ce..66dfdd4399 100644
--- a/django/db/backends/oracle/features.py
+++ b/django/db/backends/oracle/features.py
@@ -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',
+ }
diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py
index f8d2ea1286..f11558c791 100644
--- a/django/db/backends/postgresql/features.py
+++ b/django/db/backends/postgresql/features.py
@@ -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
@@ -62,6 +59,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
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
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 1b6f99a58c..08c8eb70b9 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -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
@@ -52,6 +46,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
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:
with self.connection.cursor() as cursor, transaction.atomic():
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 662fc889e5..c5f5bb7707 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -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`
-------------------------
diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py
index 910082510a..7ed96abd37 100644
--- a/tests/inspectdb/tests.py
+++ b/tests/inspectdb/tests.py
@@ -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):
diff --git a/tests/introspection/tests.py b/tests/introspection/tests.py
index bafd620232..8ca5c3af3b 100644
--- a/tests/introspection/tests.py
+++ b/tests/introspection/tests.py
@@ -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],
)
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 9aa1e239ac..0e479b5f1d 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -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):
"""