如何在 SQLAlchemy 中删除外键约束?
Posted
技术标签:
【中文标题】如何在 SQLAlchemy 中删除外键约束?【英文标题】:How do I delete a foreign key constraint in SQLAlchemy? 【发布时间】:2011-01-26 11:58:43 【问题描述】:我正在使用 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 删除外键?如何删除外键,然后删除列?
【问题讨论】:
【参考方案1】:您可以使用 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()
【讨论】:
对于任何可能遇到此问题的人 - ForeignKeyConstraint 需要从migrate
导入,而不是从 sqlalchemy
导入。【参考方案2】:
我能够通过创建一个单独的元数据实例并使用 Session.execute() 来运行原始 SQL 来实现这一点。理想情况下,会有一个专门使用 sqlalchemy 的解决方案,所以我不必使用 MySQL 特定的解决方案。但到目前为止,我还不知道有这样的解决方案。
【讨论】:
出于好奇,您执行的 SQL 是什么?【参考方案3】:我相信您可以使用 SQLAlchemy-Migrate 实现这一目标。请注意,ForeignKey 位于隔离列上。 ForeignKeyConstraint 位于表级别并将列关联在一起。如果您查看列上的 ForeignKey 对象,您会发现它引用了 ForeignKeyConstraint。
我无法测试这个想法,因为我使用的两个数据库 MS SQL 不受 SqlAlchemy-Migrate 支持,并且 sqlite 不支持“更改表”进行约束。我确实让 SQLAlchemy 尝试通过删除 sqlite 表上的引用约束来删除 FK,所以它看起来不错。 YMMV。
【讨论】:
【参考方案4】:好吧,你可以在 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)
【讨论】:
我试过了,但得到一个错误:'ForeignKey' 对象没有属性'drop'。我查看了文档,但没有看到任何方法:sqlalchemy.org/docs/reference/sqlalchemy/… 这很公平,但请向我展示 Column 具有 drop() 的 SA 文档:sqlalchemy.org/docs/reference/sqlalchemy/… 'SQLAlchemy-Migrate' 添加了 drop()、create() 和其他细节,但需要单独安装。见packages.python.org/sqlalchemy-migrate/index.html SQLAlchemy-Migrate 将 drop() 和 create() 添加到 ForeignKeyConstraint 而不是 ForeignKey。以上是关于如何在 SQLAlchemy 中删除外键约束?的主要内容,如果未能解决你的问题,请参考以下文章