sqlalchemy子句可以在没有数据库的情况下进行评估吗?

时间:2013-01-12 19:01:37

标签: python sqlalchemy

我广泛使用sqlalchemy中的ORM设施,所以在很多情况下,我已经从数据库加载了数据,并且想要检查条件或对已经加载的python对象执行计算;我还希望/需要做更多面向批处理的任务,通过对数据库执行sql(而不是根本不加载数据)可以更好地表达这些任务。我想使用相同的代码来表达两种用途的相同计算,这样我就不必向后弯曲数据库连接或者每次计算两次(一次在常规python中,再次作为查询)并运行他们不同意的风险。

假设我有:

from sqlalchemy import Integer, Column
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar = Column(Integer)

bool_clause = Foo.bar > 10
int_clause = Foo.bar + 10

a_foo = Foo(bar=5)

有没有办法获得

>>> something(bool_clause, a_foo)
False
>>> something(int_clause, a_foo)
15

没有先将a_foo保存到数据库然后执行查询?我特别希望有一种表达子句的方法,以便它也可以在数据库查询的上下文中使用,但是在没有它的情况下仍然有用。

一种选择是将条款更改为函数:

bool_clause = lambda foo=Foo: foo.bar > 10
int_clause = lambda foo=Foo: foo.bar + 10
>>> bool_clause(a_foo)
False
>>> int_clause(a_foo)
15

但我发现这比表达条款的原始方式更不易读。

1 个答案:

答案 0 :(得分:6)

有几种方法可以接近这种事情。

一种方法是,在SQLAlchemy中有一个模块,由Query.update()和Query.delete()方法使用,这个方法称为sqlalchemy.orm.evaluator。它只能表达一组非常有限的表达式运算符:

>>> from sqlalchemy.orm.evaluator import EvaluatorCompiler
>>> print EvaluatorCompiler().process(bool_clause)(a_foo)
False
>>> print EvaluatorCompiler().process(int_clause)(a_foo)
15

它没有执行更复杂的表达式,例如in_(),但是如果您想要贡献,我们可以向该模块添加任意数量的合理操作。

现在,通常完成的用例使用hybrid properties and methods。在这个用例中,我们充分利用了Python的优势,因为当我们有<anything>.someattr <some operator> <somethingelse>时,我们可以将selfcls换成<anything>。所以你的例子是:

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar = Column(Integer)

    @hybrid_method
    def bool_clause(self, other):
        return self.bar > other

    @hybrid_method
    def int_clause(self, other):
        return self.bar + other

>>> a_foo = Foo(bar=5)
>>> print a_foo.bool_clause(10)
False
>>> print a_foo.int_clause(10)
15

这实际上与你使用lambdas的建议使用相同的想法,只是表达得更好。

这两种方法也可以结合起来。评估者的一个好处是它处理or_()and_()之类的连词。如果没有这个,混合动力要求你将方法分解为“实例”和“表达”方法,如果你需要使用“和”或“或”之类的东西。