2010-03-11 134 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,所以它看起来不错。因人而异。