SQLAlchemy动态覆盖反射列

alp*_*486 2 mysql reflection sqlalchemy python-2.7

我在一个脚本中使用SA,我将使用它来定期将一个mysql表的子集从"生产"副本"复制"到开发/测试系统.我编写的代码只是为了反映源表和meta.create_all(destination_engine).由于FK的性质,我现在知道我需要use_alter=True在创建它们时在表上应用ForeignKeys,这样我就不会得到CircularDependencyErrors或其他问题.在我浏览元数据之前,我需要假设我不知道有多少FK或他们的名字.

我是SA的新手,通常是Java程序员(如你所知:D).我试图改变use_alter attr.首先迭代地:

tablesd = smeta.tables.items()
for tname, t in tablesd:
    for c in t.columns:
       for fk in c.foreign_keys:
            fk.use_alter = True
smeta.create_all(to_engine)
Run Code Online (Sandbox Code Playgroud)

编辑:重要的是要注意,在设置use_alter属性后,create_all()不会像我上面那样抛出CircularDependencyError.如果我删除该代码,create_all()不起作用.它似乎并没有从创建中删除FK ...

这显然不起作用.然后,我阅读了SA文档中的Overriding Reflected Columns,示例为:

mytable = Table('mytable', meta,
Column('id', Integer, primary_key=True), # override reflected 'id' to have primary key
Column('mydata', Unicode(50)),    # override reflected 'mydata' to be Unicode,   autoload=True)
Run Code Online (Sandbox Code Playgroud)

我猜是单独反映每个表,然后添加use_alter=TrueFK定义会起作用,但我不能假设名称和值或FK /列的#.我读过很多关于使用DeclarativeBase这样的事情的内容,但我不确定这是怎么回事......

如何获取我的任意表列表,反映它们,然后在各自的外键上覆盖use_alter选项?我是否以错误的方式思考这个问题?

alp*_*486 5

答案最终归结为问题(想象一下......).虽然每个ForeignKey对象都有一个use_alter可以设置的值,但Constraints也有一个可以设置的单独属性(我无法在API文档中找到它.在通过PyDev的调试器运行之后,我注意到前者已被设置,但所有Constraints与它们相关联的键仍然是False.我将它们设置为true:

for fk in table.foreign_keys:
    fk.use_alter=True
    fk.constraint.use_alter=True
Run Code Online (Sandbox Code Playgroud)

这似乎产生了我正在寻找的SQL,并且没有正确创建表,CircularDependencyErrors并且metadata.sorted_tables似乎工作正常,没有错误.我实际上能够重构我的代码并以正确的方式做事!

对于任何想要使用SQLAlchemy进行DB - > DB反映复杂FK的人来说,这个答案和Tyler Lesmann的文章都适合你.

*更新:*使用此方法已通过同行评审,现在用作生产代码.似乎运作良好!