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

发布于 2024-08-24 09:20:42 字数 892 浏览 4 评论 0原文

我正在使用 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'时出错(errno:150) “

如果我使用原始 SQL 执行此操作,我可以手动删除外键,然后删除该列,但我一直无法弄清楚如何使用 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

清君侧 2024-08-31 09:20:42

您可以使用 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()

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()
风蛊 2024-08-31 09:20:42

我通过创建一个单独的元数据实例并使用 Session.execute() 运行原始 SQL 来完成此任务。理想情况下,会有一个专门使用 sqlalchemy 的解决方案,这样我就不必使用特定于 MySQL 的解决方案。但到目前为止,我还不知道有这样的解决方案。

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.

戏舞 2024-08-31 09:20:42

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

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

I believe you can achieve this with SQLAlchemy-Migrate. Note that a ForeignKey is on an isolated column. A ForeignKeyConstraint is at the table level and relates the columns together. If you look at the ForeignKey object on the column you will see that it references a ForeignKeyConstraint.

I would unable to test this idea because of the two databases I use MS SQL isn't supported by SqlAlchemy-Migrate and sqlite doesn't support "alter table" for constraints. I did get SQLAlchemy to try to remove a FK via a drop on the references constraint on a sqlite table so it was looking good. YMMV.

疾风者 2024-08-31 09:20:42

好吧,您可以在 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)

Well, you can achieve this in sqlalchemy: just drop() the all the constraints before you drop() the column (theoretically, you might have multiple constraints):

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文