簡體   English   中英

如何在SQLAlchemy中刪除外鍵約束?

[英]How do I delete a foreign key constraint in SQLAlchemy?

我正在使用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刪除外鍵? 如何刪除外鍵,然后刪除列?

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

我能夠通過創建單獨的元數據實例並使用Session.execute()來運行原始SQL來實現此目的。 理想情況下,會有一個僅使用sqlalchemy的解決方案,因此我不必使用特定於MySQL的解決方案。 但截至目前,我還沒有意識到這樣的解決方案。

我相信你可以通過SQLAlchemy-Migrate實現這一目標。 請注意,ForeignKey位於隔離列上。 ForeignKeyConstraint位於表級別並將列關聯在一起。 如果查看列上的ForeignKey對象,您將看到它引用了ForeignKeyConstraint。

我無法測試這個想法因為我使用的兩個數據庫SqlAlchemy-Migrate不支持MS SQL,而sqlite不支持約束的“alter table”。 我確實讓SQLAlchemy試圖通過刪除sqlite表上的引用約束來刪除FK,所以它看起來很好。 因人而異。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM