pythonmysqlforeign-keyssqlalchemymysql-error-1025

How do I delete a foreign key constraint in SQLAlchemy?


I'm using SQLAlchemy Migrate to keep track of database changes and I'm running into an issue with removing a foreign key. I have two tables, t_new is a new table, and t_exists is an existing table. I need to add t_new, then add a foreign key to t_exists. Then I need to be able to reverse the operation (which is where I'm having trouble).

t_new = sa.Table("new", meta.metadata,
    sa.Column("new_id", sa.types.Integer, primary_key=True)
)
t_exists = sa.Table("exists", meta.metadata,
    sa.Column("exists_id", sa.types.Integer, primary_key=True),
    sa.Column(
        "new_id", 
        sa.types.Integer,
        sa.ForeignKey("new.new_id", onupdate="CASCADE", ondelete="CASCADE"),
        nullable=False
    )
)

This works fine:

t_new.create()
t_exists.c.new_id.create()

But this does not:

t_exists.c.new_id.drop()
t_new.drop()

Trying to drop the foreign key column gives an error: 1025, "Error on rename of '.\my_db_name\#sql-1b0_2e6' to '.\my_db_name\exists' (errno: 150)"

If I do this with raw SQL, i can remove the foreign key manually then remove the column, but I haven't been able to figure out how to remove the foreign key with SQLAlchemy? How can I remove the foreign key, and then the column?


Solution

  • You can do it with sqlalchemy.migrate.

    In order to make it work, I have had to create the foreign key constraint explicitly rather than implicitely with Column('fk', ForeignKey('fk_table.field')):

    Alas, instead of doing this:

    p2 = Table('tablename',
                metadata,
                Column('id', Integer, primary_key=True),
                Column('fk', ForeignKey('fk_table.field')),
                mysql_engine='InnoDB',
               )
    

    do that:

    p2 = Table('tablename',
                metadata,
                Column('id', Integer, primary_key=True),
                Column('fk', Integer, index=True),
                mysql_engine='InnoDB',
                )
    ForeignKeyConstraint(columns=[p2.c.fk], refcolumns=[p3.c.id]).create()
    

    Then the deletion process looks like this:

    def downgrade(migrate_engine):
         # First drop the constraint
         ForeignKeyConstraint(columns=[p2.c.fk], refcolumns=[p3.c.id]).drop()
         # Then drop the table
         p2.drop()