SQLAlchemy:使用两个MySQL模式中的表进行查询

时间:2014-07-02 23:14:51

标签: python mysql sql database sqlalchemy

我必须对恰好在同一个MySQL实例中的两个不同模式中传播的表进行一些查询。使用SQL,这很简单,只需在表名前加上模式名称(假设a和be是模式名称):

SELECT upeople.id AS upeople_id 
FROM a.upeople JOIN b.changes ON upeople.id = changes.changed_by

在SQLAlchemy中,似乎可以使用两个引擎来使用它。在阅读文档后,在我看来,下面的代码应该可以工作(使用两个不同的模式名称的棘手部分):

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.query import Query

Base = declarative_base(cls=DeferredReflection)
BaseId = declarative_base(cls=DeferredReflection)

class Changes(Base):
    __tablename__ = 'changes'

class UPeople(BaseId):
    __tablename__ = 'upeople'

database='mysql://jgb:XXX@localhost/a'
id_database='mysql://jgb:XXX@localhost/b'

engine = create_engine(database)
id_engine = create_engine(id_database)
Base.prepare(engine)
BaseId.prepare(id_engine)
bindings = {Changes: engine,
            UPeople: id_engine}
Session = sessionmaker(binds=bindings)
session = Session()
q = session.query(UPeople.id).join(Changes,
                                   UPeople.id == Changes.changed_by)
print q

但事实并非如此。当我执行q(例如q.all())时,它失败了。 “print q”显示没有模式名称的查询:

SELECT upeople.id AS upeople_id 
FROM upeople JOIN changes ON upeople.id = changes.changed_by

而不是我的预期:

SELECT upeople.id AS upeople_id 
FROM a.upeople JOIN b.changes ON upeople.id = changes.changed_by

我在这里缺少什么?

BTW,我发现通过添加 table_args ,例如:

class Changes(Base):
    __tablename__ = 'changes'
    __table_args__ = {'schema': 'a'}

(对于两个表),它的工作原理。但是想知道为什么其他代码没有...另外,我在声明表的类时没有模式名称,意味着我无法使用 table_args 技巧...

所以,总结一下:如何使用来自两个模式的表来查询“好方法”,并且如果可能的话,我在声明Table类时不需要包含名称,但稍后,当引擎和会话时定义了吗?

1 个答案:

答案 0 :(得分:1)

我没有找到为什么代码不起作用,我倾向于认为它是SQLAlchemy中的一个错误。但是,我找到了一种使类似代码工作的方法。它最终依赖于使用__table_args__来定义模式。但由于我在运行时之前没有模式的名称,因此我使用以下函数动态定义表的类:

def table_factory (name, tablename, schemaname):

   table_class = type(
        name,
        (Base,),
        dict (
            __tablename__ = tablename,
            __table_args__ = {'schema': schemaname}
            )
        )
    return table_class

这为名为“tablename”的表创建了一个类(名称为“name”),但是如果指定了包含模式名称。

使用此解决方案的代码与问题中的代码非常类似,如下所示:

Base = declarative_base()
database='mysql://jgb:XXX@localhost/'
Changes = table_factory (name = "Changes",
                         tablename = "changes",
                         schemaname = 'a')
UPeople = table_factory (name = "UPeople",
                         tablename = "upeople",
                         schemaname = 'b')
engine = create_engine(database)
Base.prepare(engine)
Session = sessionmaker(bind=engine)
session = Session()
q = session.query(UPeople.id).join(Changes,
                                   UPeople.id == Changes.changed_by)
print q

现在,它打印出来:

SELECT b.upeople.id AS b_upeople_id 
FROM b.upeople JOIN a.changes ON b.upeople.id = a.changes.changed_by

其中包括模式名称。