我广泛使用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
但我发现这比表达条款的原始方式更不易读。
答案 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>
时,我们可以将self
和cls
换成<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_()
之类的连词。如果没有这个,混合动力要求你将方法分解为“实例”和“表达”方法,如果你需要使用“和”或“或”之类的东西。