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

Sin*_*ion 7 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)
Run Code Online (Sandbox Code Playgroud)

有办法得到

>>> something(bool_clause, a_foo)
False
>>> something(int_clause, a_foo)
15
Run Code Online (Sandbox Code Playgroud)

没有先坚持a_foo到数据库然后执行查询?我特别想要一种表达子句的方法,以便它可以在数据库查询的上下文中使用,但是如果没有一个,它仍然有用.

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

bool_clause = lambda foo=Foo: foo.bar > 10
int_clause = lambda foo=Foo: foo.bar + 10
Run Code Online (Sandbox Code Playgroud)
>>> bool_clause(a_foo)
False
>>> int_clause(a_foo)
15
Run Code Online (Sandbox Code Playgroud)

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

zzz*_*eek 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
Run Code Online (Sandbox Code Playgroud)

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

现在,您使用的用例通常是使用混合属性和方法.在这个用例中,我们采取的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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 实际上,如果杂乱是唯一的问题,我通常使用mixins或抽象基类来做这种事情.就像某个业务对象实现了几个提供混合组合的mixin.我有一些在它们上面有几十种逻辑方法.但是,它仍然最终组合了类的命名空间上的表达式. (2认同)