Commit c06e124b authored by Andrew Godwin's avatar Andrew Godwin
Browse files

Fixed #23091: CreateModel and AddField were clashing with deferred SQL

parent 1b00738f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -546,6 +546,7 @@ class BaseDatabaseSchemaEditor(object):
                    }
                )
        # Drop any FK constraints, we'll remake them later
        fks_dropped = set()
        if old_field.rel:
            fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
            if strict and len(fk_names) != 1:
@@ -555,6 +556,7 @@ class BaseDatabaseSchemaEditor(object):
                    old_field.column,
                ))
            for fk_name in fk_names:
                fks_dropped.add((old_field.column,))
                self.execute(
                    self.sql_delete_fk % {
                        "table": self.quote_name(model._meta.db_table),
@@ -737,7 +739,7 @@ class BaseDatabaseSchemaEditor(object):
                }
            )
        # 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_column = new_field.rel.get_related_field().column
            self.execute(
+27 −0
Original line number Diff line number Diff line
@@ -1051,6 +1051,33 @@ class OperationTests(OperationTestBase):
            operation.database_backwards("test_alorwrtto", editor, new_state, project_state)
        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")
    def test_run_sql(self):
        """
+42 −0
Original line number Diff line number Diff line
@@ -331,6 +331,48 @@ class SchemaTests(TransactionTestCase):
        self.assertEqual(columns['name'][0], "TextField")
        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):
        """
        Tests simple altering of fields