10

我正在使用 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

4 回答 4

7

您可以使用 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()
于 2011-03-28T17:01:19.940 回答
3

我能够通过创建一个单独的元数据实例并使用 Session.execute() 来运行原始 SQL 来实现这一点。理想情况下,会有一个专门使用 sqlalchemy 的解决方案,所以我不必使用 MySQL 特定的解决方案。但截至目前,我不知道有这样的解决方案。

于 2010-03-11T19:23:44.230 回答
0

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

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

于 2011-02-22T16:38:35.650 回答
-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)
于 2010-03-15T20:12:48.490 回答