[1.7.x] Fixed #23091: CreateModel and AddField were clashing with deferred SQL
This commit is contained in:
parent
99f3a65c73
commit
a918c60c37
|
@ -546,6 +546,7 @@ class BaseDatabaseSchemaEditor(object):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Drop any FK constraints, we'll remake them later
|
# Drop any FK constraints, we'll remake them later
|
||||||
|
fks_dropped = set()
|
||||||
if old_field.rel:
|
if old_field.rel:
|
||||||
fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
|
fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
|
||||||
if strict and len(fk_names) != 1:
|
if strict and len(fk_names) != 1:
|
||||||
|
@ -555,6 +556,7 @@ class BaseDatabaseSchemaEditor(object):
|
||||||
old_field.column,
|
old_field.column,
|
||||||
))
|
))
|
||||||
for fk_name in fk_names:
|
for fk_name in fk_names:
|
||||||
|
fks_dropped.add((old_field.column,))
|
||||||
self.execute(
|
self.execute(
|
||||||
self.sql_delete_fk % {
|
self.sql_delete_fk % {
|
||||||
"table": self.quote_name(model._meta.db_table),
|
"table": self.quote_name(model._meta.db_table),
|
||||||
|
@ -737,7 +739,7 @@ class BaseDatabaseSchemaEditor(object):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Does it have a foreign key?
|
# Does it have a foreign key?
|
||||||
if new_field.rel:
|
if new_field.rel and fks_dropped:
|
||||||
to_table = new_field.rel.to._meta.db_table
|
to_table = new_field.rel.to._meta.db_table
|
||||||
to_column = new_field.rel.get_related_field().column
|
to_column = new_field.rel.get_related_field().column
|
||||||
self.execute(
|
self.execute(
|
||||||
|
|
|
@ -1051,6 +1051,33 @@ class OperationTests(OperationTestBase):
|
||||||
operation.database_backwards("test_alorwrtto", editor, new_state, project_state)
|
operation.database_backwards("test_alorwrtto", editor, new_state, project_state)
|
||||||
self.assertColumnNotExists("test_alorwrtto_rider", "_order")
|
self.assertColumnNotExists("test_alorwrtto_rider", "_order")
|
||||||
|
|
||||||
|
def test_alter_fk(self):
|
||||||
|
"""
|
||||||
|
Tests that creating and then altering an FK works correctly
|
||||||
|
and deals with the pending SQL (#23091)
|
||||||
|
"""
|
||||||
|
project_state = self.set_up_test_model("test_alfk")
|
||||||
|
# Test adding and then altering the FK in one go
|
||||||
|
create_operation = migrations.CreateModel(
|
||||||
|
name="Rider",
|
||||||
|
fields=[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("pony", models.ForeignKey(to="Pony")),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
create_state = project_state.clone()
|
||||||
|
create_operation.state_forwards("test_alfk", create_state)
|
||||||
|
alter_operation = migrations.AlterField(
|
||||||
|
model_name='Rider',
|
||||||
|
name='pony',
|
||||||
|
field=models.ForeignKey(editable=False, to="Pony"),
|
||||||
|
)
|
||||||
|
alter_state = create_state.clone()
|
||||||
|
alter_operation.state_forwards("test_alfk", alter_state)
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
create_operation.database_forwards("test_alfk", editor, project_state, create_state)
|
||||||
|
alter_operation.database_forwards("test_alfk", editor, create_state, alter_state)
|
||||||
|
|
||||||
@unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
|
@unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
|
||||||
def test_run_sql(self):
|
def test_run_sql(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -331,6 +331,48 @@ class SchemaTests(TransactionTestCase):
|
||||||
self.assertEqual(columns['name'][0], "TextField")
|
self.assertEqual(columns['name'][0], "TextField")
|
||||||
self.assertEqual(bool(columns['name'][1][6]), False)
|
self.assertEqual(bool(columns['name'][1][6]), False)
|
||||||
|
|
||||||
|
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
|
||||||
|
def test_alter_fk(self):
|
||||||
|
"""
|
||||||
|
Tests altering of FKs
|
||||||
|
"""
|
||||||
|
# Create the table
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(Author)
|
||||||
|
editor.create_model(Book)
|
||||||
|
# Ensure the field is right to begin with
|
||||||
|
columns = self.column_classes(Book)
|
||||||
|
self.assertEqual(columns['author_id'][0], "IntegerField")
|
||||||
|
# Make sure the FK constraint is present
|
||||||
|
constraints = self.get_constraints(Book._meta.db_table)
|
||||||
|
for name, details in constraints.items():
|
||||||
|
if details['columns'] == ["author_id"] and details['foreign_key']:
|
||||||
|
self.assertEqual(details['foreign_key'], ('schema_author', 'id'))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.fail("No FK constraint for author_id found")
|
||||||
|
# Alter the FK
|
||||||
|
new_field = ForeignKey(Author, editable=False)
|
||||||
|
new_field.set_attributes_from_name("author")
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.alter_field(
|
||||||
|
Book,
|
||||||
|
Book._meta.get_field_by_name("author")[0],
|
||||||
|
new_field,
|
||||||
|
strict=True,
|
||||||
|
)
|
||||||
|
# Ensure the field is right afterwards
|
||||||
|
columns = self.column_classes(Book)
|
||||||
|
self.assertEqual(columns['author_id'][0], "IntegerField")
|
||||||
|
# Make sure the FK constraint is present
|
||||||
|
constraints = self.get_constraints(Book._meta.db_table)
|
||||||
|
for name, details in constraints.items():
|
||||||
|
if details['columns'] == ["author_id"] and details['foreign_key']:
|
||||||
|
self.assertEqual(details['foreign_key'], ('schema_author', 'id'))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.fail("No FK constraint for author_id found")
|
||||||
|
|
||||||
def test_rename(self):
|
def test_rename(self):
|
||||||
"""
|
"""
|
||||||
Tests simple altering of fields
|
Tests simple altering of fields
|
||||||
|
|
Loading…
Reference in New Issue