How do I delete a foreign key constraint in SQLAlchemy?

11,527

Solution 1

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()

Solution 2

I was able to accomplish this by creating a separate metadata instance and using Session.execute() to run raw SQL. Ideally, there would be a solution that uses sqlalchemy exclusively, so I wouldn't have to use MySQL-specific solutions. But as of now, I am not aware of such a solution.

Share:
11,527
Travis
Author by

Travis

Co-founder of Annotary.

Updated on June 04, 2022

Comments

  • Travis
    Travis about 2 years

    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?

  • Travis
    Travis over 14 years
    I tried this out, but got an error: 'ForeignKey' object has no attribute 'drop'. I checked out the docs but didn't see any way to do this: sqlalchemy.org/docs/reference/sqlalchemy/…
  • van
    van over 14 years
    this is fair, but show me the documentation of SA where Column has drop(): sqlalchemy.org/docs/reference/sqlalchemy/…
  • OrganicPanda
    OrganicPanda over 13 years
    'SQLAlchemy-Migrate' adds drop(), create() and other niceties but it needs to be installed separately. See packages.python.org/sqlalchemy-migrate/index.html
  • Ben
    Ben over 13 years
    SQLAlchemy-Migrate adds drop() and create() to ForeignKeyConstraint not ForeignKey.
  • a paid nerd
    a paid nerd about 13 years
    Out of curiosity, what was the SQL you executed?
  • mjallday
    mjallday over 11 years
    For anyone who may run into this - ForeignKeyConstraint needs to be imported from migrate not from sqlalchemy.