如何在SQLAlchemy中删除外键约束?

时间:2010-03-11 17:25:59

标签: python mysql foreign-keys sqlalchemy mysql-error-1025

我正在使用SQLAlchemy Migrate来跟踪数据库更改,而且我遇到了删除外键的问题。我有两个表,t_new是一个新表,t_exists是一个现有的表。我需要添加t_new,然后向t_exists添加一个外键。然后我需要能够扭转操作(这是我遇到麻烦的地方)。

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

这很好用:

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

但这不是:

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

尝试删除外键列会出现错误:1025,“将'。\ my_db_name \#sql-1b0_2e6'重命名为'。\ my_db_name \ exists'(错误号:150)”时出错“

如果我使用原始SQL执行此操作,我可以手动删除外键然后删除列,但我无法弄清楚如何使用SQLAlchemy删除外键?如何删除外键,然后删除列?

4 个答案:

答案 0 :(得分:5)

您可以使用sqlalchemy.migrate。

为了使它工作,我必须显式创建外键约束而不是使用Column('fk',ForeignKey('fk_table.field'))隐含地创建外键约束:

唉,而不是这样做:

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

这样做:

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

然后删除过程如下所示:

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

答案 1 :(得分:3)

我能够通过创建单独的元数据实例并使用Session.execute()来运行原始SQL来实现此目的。理想情况下,会有一个仅使用sqlalchemy的解决方案,因此我不必使用特定于MySQL的解决方案。但截至目前,我还没有意识到这样的解决方案。

答案 2 :(得分:0)

我相信你可以通过SQLAlchemy-Migrate实现这一目标。请注意,ForeignKey位于隔离列上。 ForeignKeyConstraint位于表级别并将列关联在一起。如果查看列上的ForeignKey对象,您将看到它引用了ForeignKeyConstraint。

我无法测试这个想法,因为我使用的是两个数据库.SqlAlchemy-Migrate不支持MS SQL,而sqlite不支持约束的“alter table”。我确实让SQLAlchemy试图通过删除sqlite表上的引用约束来删除FK,所以它看起来很好。 YMMV。

答案 3 :(得分:-1)

好吧,你可以在sqlalchemy中实现这一点:只需drop()drop()之前的所有约束(理论上,你可能有多个约束):

def drop_column(column):
    for fk in column.table.foreign_keys:
        if fk.column == column:
            print 'deleting fk ', fk
            fk.drop()
    column.drop()

drop_column(t_exists.c.new_id)