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

时间:2014-12-30 14:44:52

标签: python sqlalchemy

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

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

DBSession.query(MyObject).filter(self.check_attributes(MyObject) == True).all()

DBSession.query(MyObject).filter(self.check_attributes(MyObject)).all()

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

2 个答案:

答案 0 :(得分:13)

正如我在评论中所说,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

答案 1 :(得分:1)

如果通过&#34;使用功能&#34;你的意思是在函数内部编写过滤器,你当然可以 - 你只需要将正确的参数传递给它(查询)并在适当的地方使用它的返回(过滤后的查询)

让我们以SQLAlchemy的教程为例:

wendy = session.query(User).filter_by(name='wendy').one() 

您可以轻松地将过滤器移动到某个功能:

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

wendy = my_filter(session.query(User)).one() 

然而,如果通过&#34;检查对象是否有某些属性的函数,并根据结果返回布尔值&#34;你的意思是一个接受数据库记录作为参数的函数,我不认为它可以完成(不破坏使用SQL的整个目的)。

- 编辑 - 正如doog abides指出的那样,hybrid扩展程序在不对数据库记录进行操作的情况下,会为许多实际操作提供相同的功能目的。


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

all_users = session.query(User).all()
wendy= filter( lambda u:u.name=='wendy', all_users )

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