Refs #31630 -- Added CharField and IntegerField to DatabaseFeatures.introspected_field_types.

CockroachDB introspects CharField as TextField and IntegerField as
BigIntegerField.
This commit is contained in:
Tim Graham 2020-06-01 21:59:03 -04:00 committed by Mariusz Felisiak
parent e24b63fe85
commit a7b4a04d6c
4 changed files with 53 additions and 43 deletions

View File

@ -133,8 +133,10 @@ class BaseDatabaseFeatures:
'BigIntegerField': 'BigIntegerField', 'BigIntegerField': 'BigIntegerField',
'BinaryField': 'BinaryField', 'BinaryField': 'BinaryField',
'BooleanField': 'BooleanField', 'BooleanField': 'BooleanField',
'CharField': 'CharField',
'DurationField': 'DurationField', 'DurationField': 'DurationField',
'GenericIPAddressField': 'GenericIPAddressField', 'GenericIPAddressField': 'GenericIPAddressField',
'IntegerField': 'IntegerField',
'PositiveBigIntegerField': 'PositiveBigIntegerField', 'PositiveBigIntegerField': 'PositiveBigIntegerField',
'PositiveIntegerField': 'PositiveIntegerField', 'PositiveIntegerField': 'PositiveIntegerField',
'PositiveSmallIntegerField': 'PositiveSmallIntegerField', 'PositiveSmallIntegerField': 'PositiveSmallIntegerField',

View File

@ -61,10 +61,10 @@ class InspectDBTestCase(TestCase):
"""Test introspection of various Django field types""" """Test introspection of various Django field types"""
assertFieldType = self.make_field_type_asserter() assertFieldType = self.make_field_type_asserter()
introspected_field_types = connection.features.introspected_field_types introspected_field_types = connection.features.introspected_field_types
char_field_type = introspected_field_types['CharField']
# Inspecting Oracle DB doesn't produce correct results (#19884): # Inspecting Oracle DB doesn't produce correct results (#19884):
# - it reports fields as blank=True when they aren't. # - it reports fields as blank=True when they aren't.
if not connection.features.interprets_empty_strings_as_nulls: if not connection.features.interprets_empty_strings_as_nulls and char_field_type == 'CharField':
assertFieldType('char_field', "models.CharField(max_length=10)") assertFieldType('char_field', "models.CharField(max_length=10)")
assertFieldType('null_char_field', "models.CharField(max_length=10, blank=True, null=True)") assertFieldType('null_char_field', "models.CharField(max_length=10, blank=True, null=True)")
assertFieldType('email_field', "models.CharField(max_length=254)") assertFieldType('email_field', "models.CharField(max_length=254)")
@ -73,6 +73,15 @@ class InspectDBTestCase(TestCase):
assertFieldType('slug_field', "models.CharField(max_length=50)") assertFieldType('slug_field', "models.CharField(max_length=50)")
assertFieldType('text_field', "models.TextField()") assertFieldType('text_field', "models.TextField()")
assertFieldType('url_field', "models.CharField(max_length=200)") assertFieldType('url_field', "models.CharField(max_length=200)")
if char_field_type == 'TextField':
assertFieldType('char_field', 'models.TextField()')
assertFieldType('null_char_field', 'models.TextField(blank=True, null=True)')
assertFieldType('email_field', 'models.TextField()')
assertFieldType('file_field', 'models.TextField()')
assertFieldType('file_path_field', 'models.TextField()')
assertFieldType('slug_field', 'models.TextField()')
assertFieldType('text_field', 'models.TextField()')
assertFieldType('url_field', 'models.TextField()')
assertFieldType('date_field', "models.DateField()") assertFieldType('date_field', "models.DateField()")
assertFieldType('date_time_field', "models.DateTimeField()") assertFieldType('date_time_field', "models.DateTimeField()")
if introspected_field_types['GenericIPAddressField'] == 'GenericIPAddressField': if introspected_field_types['GenericIPAddressField'] == 'GenericIPAddressField':
@ -117,7 +126,7 @@ class InspectDBTestCase(TestCase):
"as this database handles decimal fields as float") "as this database handles decimal fields as float")
assertFieldType('float_field', "models.FloatField()") assertFieldType('float_field', "models.FloatField()")
assertFieldType('int_field', "models.IntegerField()") assertFieldType('int_field', 'models.%s()' % introspected_field_types['IntegerField'])
assertFieldType('pos_int_field', 'models.%s()' % introspected_field_types['PositiveIntegerField']) assertFieldType('pos_int_field', 'models.%s()' % introspected_field_types['PositiveIntegerField'])
assertFieldType('pos_big_int_field', 'models.%s()' % introspected_field_types['PositiveBigIntegerField']) assertFieldType('pos_big_int_field', 'models.%s()' % introspected_field_types['PositiveBigIntegerField'])
assertFieldType('pos_small_int_field', 'models.%s()' % introspected_field_types['PositiveSmallIntegerField']) assertFieldType('pos_small_int_field', 'models.%s()' % introspected_field_types['PositiveSmallIntegerField'])
@ -152,19 +161,20 @@ class InspectDBTestCase(TestCase):
def test_digits_column_name_introspection(self): def test_digits_column_name_introspection(self):
"""Introspection of column names consist/start with digits (#16536/#17676)""" """Introspection of column names consist/start with digits (#16536/#17676)"""
char_field_type = connection.features.introspected_field_types['CharField']
out = StringIO() out = StringIO()
call_command('inspectdb', 'inspectdb_digitsincolumnname', stdout=out) call_command('inspectdb', 'inspectdb_digitsincolumnname', stdout=out)
output = out.getvalue() output = out.getvalue()
error_message = "inspectdb generated a model field name which is a number" error_message = "inspectdb generated a model field name which is a number"
self.assertNotIn(" 123 = models.CharField", output, msg=error_message) self.assertNotIn(' 123 = models.%s' % char_field_type, output, msg=error_message)
self.assertIn("number_123 = models.CharField", output) self.assertIn('number_123 = models.%s' % char_field_type, output)
error_message = "inspectdb generated a model field name which starts with a digit" error_message = "inspectdb generated a model field name which starts with a digit"
self.assertNotIn(" 4extra = models.CharField", output, msg=error_message) self.assertNotIn(' 4extra = models.%s' % char_field_type, output, msg=error_message)
self.assertIn("number_4extra = models.CharField", output) self.assertIn('number_4extra = models.%s' % char_field_type, output)
self.assertNotIn(" 45extra = models.CharField", output, msg=error_message) self.assertNotIn(' 45extra = models.%s' % char_field_type, output, msg=error_message)
self.assertIn("number_45extra = models.CharField", output) self.assertIn('number_45extra = models.%s' % char_field_type, output)
def test_special_column_name_introspection(self): def test_special_column_name_introspection(self):
""" """
@ -175,12 +185,13 @@ class InspectDBTestCase(TestCase):
call_command('inspectdb', table_name_filter=special_table_only, stdout=out) call_command('inspectdb', table_name_filter=special_table_only, stdout=out)
output = out.getvalue() output = out.getvalue()
base_name = connection.introspection.identifier_converter('Field') base_name = connection.introspection.identifier_converter('Field')
self.assertIn("field = models.IntegerField()", output) integer_field_type = connection.features.introspected_field_types['IntegerField']
self.assertIn("field_field = models.IntegerField(db_column='%s_')" % base_name, output) self.assertIn("field = models.%s()" % integer_field_type, output)
self.assertIn("field_field_0 = models.IntegerField(db_column='%s__')" % base_name, output) self.assertIn("field_field = models.%s(db_column='%s_')" % (integer_field_type, base_name), output)
self.assertIn("field_field_1 = models.IntegerField(db_column='__field')", output) self.assertIn("field_field_0 = models.%s(db_column='%s__')" % (integer_field_type, base_name), output)
self.assertIn("prc_x = models.IntegerField(db_column='prc(%) x')", output) self.assertIn("field_field_1 = models.%s(db_column='__field')" % integer_field_type, output)
self.assertIn("tamaño = models.IntegerField()", output) self.assertIn("prc_x = models.{}(db_column='prc(%) x')".format(integer_field_type), output)
self.assertIn("tamaño = models.%s()" % integer_field_type, output)
def test_table_name_introspection(self): def test_table_name_introspection(self):
""" """

View File

@ -80,15 +80,12 @@ class IntrospectionTests(TransactionTestCase):
self.assertEqual( self.assertEqual(
[connection.introspection.get_field_type(r[1], r) for r in desc], [connection.introspection.get_field_type(r[1], r) for r in desc],
[ [
connection.features.introspected_field_types['AutoField'], connection.features.introspected_field_types[field] for field in (
'CharField', 'AutoField', 'CharField', 'CharField', 'CharField',
'CharField', 'BigIntegerField', 'BinaryField', 'SmallIntegerField',
'CharField', 'DurationField',
connection.features.introspected_field_types['BigIntegerField'], )
connection.features.introspected_field_types['BinaryField'], ],
connection.features.introspected_field_types['SmallIntegerField'],
connection.features.introspected_field_types['DurationField'],
]
) )
def test_get_table_description_col_lengths(self): def test_get_table_description_col_lengths(self):

View File

@ -498,7 +498,7 @@ class SchemaTests(TransactionTestCase):
self.assertFalse(any(drop_default_sql in query['sql'] for query in ctx.captured_queries)) self.assertFalse(any(drop_default_sql in query['sql'] for query in ctx.captured_queries))
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['age'][0], "IntegerField") self.assertEqual(columns['age'][0], connection.features.introspected_field_types['IntegerField'])
self.assertTrue(columns['age'][1][6]) self.assertTrue(columns['age'][1][6])
def test_add_field_remove_field(self): def test_add_field_remove_field(self):
@ -532,7 +532,7 @@ class SchemaTests(TransactionTestCase):
editor.add_field(Author, new_field) editor.add_field(Author, new_field)
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['surname'][0], "CharField") self.assertEqual(columns['surname'][0], connection.features.introspected_field_types['CharField'])
self.assertEqual(columns['surname'][1][6], self.assertEqual(columns['surname'][1][6],
connection.features.interprets_empty_strings_as_nulls) connection.features.interprets_empty_strings_as_nulls)
@ -592,7 +592,7 @@ class SchemaTests(TransactionTestCase):
# Ensure the field is there # Ensure the field is there
columns = self.column_classes(Author) columns = self.column_classes(Author)
field_type, field_info = columns['thing'] field_type, field_info = columns['thing']
self.assertEqual(field_type, 'IntegerField') self.assertEqual(field_type, connection.features.introspected_field_types['IntegerField'])
# Make sure the values were transformed correctly # Make sure the values were transformed correctly
self.assertEqual(Author.objects.extra(where=["thing = 1"]).count(), 2) self.assertEqual(Author.objects.extra(where=["thing = 1"]).count(), 2)
@ -640,7 +640,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(Author) editor.create_model(Author)
# Ensure the field is right to begin with # Ensure the field is right to begin with
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField") self.assertEqual(columns['name'][0], connection.features.introspected_field_types['CharField'])
self.assertEqual(bool(columns['name'][1][6]), bool(connection.features.interprets_empty_strings_as_nulls)) self.assertEqual(bool(columns['name'][1][6]), bool(connection.features.interprets_empty_strings_as_nulls))
# Alter the name field to a TextField # Alter the name field to a TextField
old_field = Author._meta.get_field("name") old_field = Author._meta.get_field("name")
@ -1022,7 +1022,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(Book) editor.create_model(Book)
# Ensure the field is right to begin with # Ensure the field is right to begin with
columns = self.column_classes(Book) columns = self.column_classes(Book)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
self.assertForeignKeyExists(Book, 'author_id', 'schema_author') self.assertForeignKeyExists(Book, 'author_id', 'schema_author')
# Alter the FK # Alter the FK
old_field = Book._meta.get_field("author") old_field = Book._meta.get_field("author")
@ -1032,7 +1032,7 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(Book, old_field, new_field, strict=True) editor.alter_field(Book, old_field, new_field, strict=True)
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(Book) columns = self.column_classes(Book)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
self.assertForeignKeyExists(Book, 'author_id', 'schema_author') self.assertForeignKeyExists(Book, 'author_id', 'schema_author')
@skipUnlessDBFeature('supports_foreign_keys') @skipUnlessDBFeature('supports_foreign_keys')
@ -1078,7 +1078,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(BookWithO2O) editor.create_model(BookWithO2O)
# Ensure the field is right to begin with # Ensure the field is right to begin with
columns = self.column_classes(BookWithO2O) columns = self.column_classes(BookWithO2O)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
# Ensure the field is unique # Ensure the field is unique
author = Author.objects.create(name="Joe") author = Author.objects.create(name="Joe")
BookWithO2O.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now()) BookWithO2O.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now())
@ -1094,7 +1094,7 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(BookWithO2O, old_field, new_field, strict=True) editor.alter_field(BookWithO2O, old_field, new_field, strict=True)
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(Book) columns = self.column_classes(Book)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
# Ensure the field is not unique anymore # Ensure the field is not unique anymore
Book.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now()) Book.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now())
Book.objects.create(author=author, title="Django 2", pub_date=datetime.datetime.now()) Book.objects.create(author=author, title="Django 2", pub_date=datetime.datetime.now())
@ -1111,7 +1111,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(Book) editor.create_model(Book)
# Ensure the field is right to begin with # Ensure the field is right to begin with
columns = self.column_classes(Book) columns = self.column_classes(Book)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
# Ensure the field is not unique # Ensure the field is not unique
author = Author.objects.create(name="Joe") author = Author.objects.create(name="Joe")
Book.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now()) Book.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now())
@ -1126,7 +1126,7 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(Book, old_field, new_field, strict=True) editor.alter_field(Book, old_field, new_field, strict=True)
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(BookWithO2O) columns = self.column_classes(BookWithO2O)
self.assertEqual(columns['author_id'][0], "IntegerField") self.assertEqual(columns['author_id'][0], connection.features.introspected_field_types['IntegerField'])
# Ensure the field is unique now # Ensure the field is unique now
BookWithO2O.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now()) BookWithO2O.objects.create(author=author, title="Django 1", pub_date=datetime.datetime.now())
with self.assertRaises(IntegrityError): with self.assertRaises(IntegrityError):
@ -1438,7 +1438,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(Author) editor.create_model(Author)
# Ensure the field is right to begin with # Ensure the field is right to begin with
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField") self.assertEqual(columns['name'][0], connection.features.introspected_field_types['CharField'])
self.assertNotIn("display_name", columns) self.assertNotIn("display_name", columns)
# Alter the name field's name # Alter the name field's name
old_field = Author._meta.get_field("name") old_field = Author._meta.get_field("name")
@ -1448,7 +1448,7 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(Author, old_field, new_field, strict=True) editor.alter_field(Author, old_field, new_field, strict=True)
# Ensure the field is right afterwards # Ensure the field is right afterwards
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['display_name'][0], "CharField") self.assertEqual(columns['display_name'][0], connection.features.introspected_field_types['CharField'])
self.assertNotIn("name", columns) self.assertNotIn("name", columns)
@isolate_apps('schema') @isolate_apps('schema')
@ -1516,7 +1516,7 @@ class SchemaTests(TransactionTestCase):
editor.create_model(LocalBookWithM2M) editor.create_model(LocalBookWithM2M)
# Ensure there is now an m2m table there # Ensure there is now an m2m table there
columns = self.column_classes(LocalBookWithM2M._meta.get_field("tags").remote_field.through) columns = self.column_classes(LocalBookWithM2M._meta.get_field("tags").remote_field.through)
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField") self.assertEqual(columns['tagm2mtest_id'][0], connection.features.introspected_field_types['IntegerField'])
def test_m2m_create(self): def test_m2m_create(self):
self._test_m2m_create(ManyToManyField) self._test_m2m_create(ManyToManyField)
@ -1555,8 +1555,8 @@ class SchemaTests(TransactionTestCase):
editor.create_model(LocalBookWithM2MThrough) editor.create_model(LocalBookWithM2MThrough)
# Ensure there is now an m2m table there # Ensure there is now an m2m table there
columns = self.column_classes(LocalTagThrough) columns = self.column_classes(LocalTagThrough)
self.assertEqual(columns['book_id'][0], "IntegerField") self.assertEqual(columns['book_id'][0], connection.features.introspected_field_types['IntegerField'])
self.assertEqual(columns['tag_id'][0], "IntegerField") self.assertEqual(columns['tag_id'][0], connection.features.introspected_field_types['IntegerField'])
def test_m2m_create_through(self): def test_m2m_create_through(self):
self._test_m2m_create_through(ManyToManyField) self._test_m2m_create_through(ManyToManyField)
@ -1595,7 +1595,7 @@ class SchemaTests(TransactionTestCase):
editor.add_field(LocalAuthorWithM2M, new_field) editor.add_field(LocalAuthorWithM2M, new_field)
# Ensure there is now an m2m table there # Ensure there is now an m2m table there
columns = self.column_classes(new_field.remote_field.through) columns = self.column_classes(new_field.remote_field.through)
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField") self.assertEqual(columns['tagm2mtest_id'][0], connection.features.introspected_field_types['IntegerField'])
# "Alter" the field. This should not rename the DB table to itself. # "Alter" the field. This should not rename the DB table to itself.
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
@ -2268,14 +2268,14 @@ class SchemaTests(TransactionTestCase):
editor.create_model(Book) editor.create_model(Book)
# Ensure the table is there to begin with # Ensure the table is there to begin with
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField") self.assertEqual(columns['name'][0], connection.features.introspected_field_types['CharField'])
# Alter the table # Alter the table
with connection.schema_editor(atomic=connection.features.supports_atomic_references_rename) as editor: with connection.schema_editor(atomic=connection.features.supports_atomic_references_rename) as editor:
editor.alter_db_table(Author, "schema_author", "schema_otherauthor") editor.alter_db_table(Author, "schema_author", "schema_otherauthor")
# Ensure the table is there afterwards # Ensure the table is there afterwards
Author._meta.db_table = "schema_otherauthor" Author._meta.db_table = "schema_otherauthor"
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField") self.assertEqual(columns['name'][0], connection.features.introspected_field_types['CharField'])
# Ensure the foreign key reference was updated # Ensure the foreign key reference was updated
self.assertForeignKeyExists(Book, "author_id", "schema_otherauthor") self.assertForeignKeyExists(Book, "author_id", "schema_otherauthor")
# Alter the table again # Alter the table again
@ -2284,7 +2284,7 @@ class SchemaTests(TransactionTestCase):
# Ensure the table is still there # Ensure the table is still there
Author._meta.db_table = "schema_author" Author._meta.db_table = "schema_author"
columns = self.column_classes(Author) columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField") self.assertEqual(columns['name'][0], connection.features.introspected_field_types['CharField'])
def test_add_remove_index(self): def test_add_remove_index(self):
""" """