2010-03-11 141 views
7

我使用SQLAlchemy的遷移跟蹤數據庫的變化和我遇到的問題與刪除的外鍵。我有兩個表,t_new是一個新表,而t_exists是一個現有的表。我需要添加t_new,然後向t_exists添加一個外鍵。然後我需要能夠扭轉操作(這是我遇到麻煩的地方)。如何在SQLAlchemy中刪除外鍵約束?

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執行此操作,我可以刪除f手動鍵入關鍵字然後刪除列,但我一直無法弄清楚如何使用SQLAlchemy刪除外鍵?我如何刪除外鍵,然後刪除列?

回答

5

你可以用sqlalchemy.migrate做到這一點。

爲了使其工作,我不得不創建外鍵約束明確,而不是用隱含列(「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() 
+2

對於任何可能遇到此問題的人 - ForeignKeyConstraint需要從'migrate'中導入,而不是從'sqlalchemy'中導入。 – mjallday

2

我能夠通過創建一個單獨的元數據實例,並使用Session.execute()運行原始SQL來做到這一點。理想情況下,會有一個只使用sqlalchemy的解決方案,所以我不必使用MySQL特定的解決方案。但截至目前,我不知道這樣的解決方案。

+3

出於好奇,究竟是什麼SQL你執行? –

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

我試過了,但出現錯誤:'ForeignKey'對象沒有'drop'屬性。我檢查了文檔,但沒有看到任何方式做到這一點:http://www.sqlalchemy.org/docs/reference/sqlalchemy/schema.html?highlight=foreignkey#sqlalchemy.schema。ForeignKey – Travis

+0

這很公平,但向我展示了Column已放置(SA)的SA的文檔:http://www.sqlalchemy.org/docs/reference/sqlalchemy/schema.html?highlight=foreignkey#sqlalchemy.schema.Column – van

+0

'SQLAlchemy-Migrate'添加了drop(),create()和其他細節,但需要單獨安裝。請參閱http://packages.python.org/sqlalchemy-migrate/index.html – OrganicPanda

0

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

我就無法執行,因爲這兩個數據庫中我使用MS SQL不SQLAlchemy的,遷移和SQLite支持不支持「ALTER TABLE」爲約束,以測試這個想法。我沒有得到SQLAlchemy嘗試通過在sqlite表上的引用約束上的刪除來刪除FK,所以它看起來不錯。因人而異。