是否可以在SQLAlchemy过滤器中使用函数?

use*_*472 8 python sqlalchemy

我有一个函数检查对象的某些属性,并根据结果返回布尔值.在过滤器中编写它太复杂了,但它可以工作并返回正确的值.

现在我想使用sqlalchemy返回此函数返回True的所有对象.我试过了:

DBSession.query(MyObject).filter(self.check_attributes(MyObject) == True).all()
Run Code Online (Sandbox Code Playgroud)

DBSession.query(MyObject).filter(self.check_attributes(MyObject)).all()
Run Code Online (Sandbox Code Playgroud)

两者都未能选择正确的对象.我究竟做错了什么?

doo*_*des 17

正如我在评论中所说,hybrid_method/ hybrid_property是适用于您的用例的模式.它起初可能看起来很复杂,但实际上很简单.该函数的第一个版本与Python方法或属性完全相同,第二个版本充当类方法.SQLAlchemy过滤器在类上工作以生成SQL.

这只是一个无用的例子,但是therabouts你的例子可能会有一个复杂的计算.

如果您不需要传递任何参数,那么我建议使用hybrid_property.

class MyObject(Model):
  name = Column(String)
  num = Column(Integer)

  @hybrid_method
  def therabouts(self, n):
     return self.num > n - 5 and self.num <= n + 5

  @therabouts.expression
  def therabouts(cls, n):
     return and_(cls.num > n - 5, cls.num <= n + 5)

  @hybrid_property
  def is_al(self):
     return self.name.lower().startswith('al')

  @is_al.expression
  def is_al(cls):
     return cls.name.ilike('al%')

# When used as a class method @thereabouts.expression is called
near20 = session.query(MyObject).filter(MyObject.therabouts(20)).first()

# When used as an instance, @hybrid_method is called
near20.therabouts(20) # True
near20.therabouts(22) # Maybe True
near20.therabouts(50) # False

# filter example (class)
all_als = session.query(MyObject).filter(MyObject.is_al).all()
for al in all_als:
  print al.name
# output Alan, Alanzo, Albert...

# instance example (self)
bob = MyObject(name='Robert')
print bob.is_al # False
Run Code Online (Sandbox Code Playgroud)

  • 这很有意思,我不知道`hybrid`扩展.对于任何寻找它的人,[这里是相关文档](http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/hybrid.html). (4认同)

gon*_*opp 2

如果“使用函数”是指在函数内编写过滤器,那么您当然可以 - 您只需将正确的参数传递给它(查询并在适当的位置使用它的返回值(过滤后的查询)

让我们以 SQLAlchemy 教程中的一个例子为例:

wendy = session.query(User).filter_by(name='wendy').one() 
Run Code Online (Sandbox Code Playgroud)

您可以轻松地将过滤器移动到函数中:

def my_filter(query):
    return query.filter_by(name='wendy')

wendy = my_filter(session.query(User)).one() 
Run Code Online (Sandbox Code Playgroud)

但是,如果“检查对象的某些属性并根据结果返回布尔值的函数”您的意思是接受数据库记录作为参数的函数,我认为它无法完成(不破坏整个目的)使用 SQL)。

--编辑--正如所doog abides指出的,该hybrid扩展虽然不对数据库记录进行操作,但会执行与许多实际目的相同的操作。


当然,有些人会坚持这样写:

all_users = session.query(User).all()
wendy= filter( lambda u:u.name=='wendy', all_users )
Run Code Online (Sandbox Code Playgroud)

但是,为了其他程序员和用户的理智,请不要这样做。