我在脚本中使用 SA,我将使用该脚本定期将 mysql 表的子集从“生产”副本“复制”到开发/测试系统。我编写了代码来简单地反射(reflect)源表和 meta.create_all(destination_engine)
。由于 FK 的性质,我现在知道在创建表上的外键时需要将 use_alter=True
应用到它们,这样就不会出现 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)
编辑:需要注意的是,在我像上面那样设置 use_alter 属性后,create_all() 不会抛出 CircularDependencyError 。如果我删除该代码,create_all() 将不起作用。它似乎并没有从创建中删除 FK...
这显然行不通。然后我读了Overriding Reflected Columns在 SA 文档中,示例为:
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)
我猜想单独反射(reflect)每个表,然后在 FK 定义中添加 use_alter=True
会起作用,但我无法假设 FK/列的名称和值或数量。我读了很多关于使用 DeclarativeBase
来做这样的事情,但我不太确定它是如何工作的......
如何获取任意表列表,反射(reflect)它们,然后覆盖它们各自外键上的 use_alter 选项?我是否以错误的方式思考这个问题?
最佳答案
答案最终就在问题内部(想象一下......)。虽然每个ForeignKey
对象有一个 use_alter
可以设置的值,Constraints
还有一个可以设置的单独属性(我无法在 API Documentation 中找到它。通过 PyDev 的调试器运行它后,我注意到前者已被设置,但所有与 Constraints
关联的键仍然是 False
。我这样将它们设置为 true:
for fk in table.foreign_keys:
fk.use_alter=True
fk.constraint.use_alter=True
这似乎产生了我正在寻找的 SQL,并且表已正确创建,没有 CircularDependencyErrors
和metadata.sorted_tables
似乎工作正常,没有错误。我实际上能够重构我的代码并以正确的方式做事!
对于任何想要使用 SQLAlchemy 进行 DB-->DB 反射(reflect)复杂 FK 的人来说,这个答案和 Tyler Lesmann's article适合你。
*更新:* 使用此方法已通过同行评审,现已用作生产代码。看起来效果很好!
关于mysql - SQLAlchemy 动态覆盖反射列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12303439/