SQLAlchemy:使用`and`和`or`时出现意外结果
问题内容:
我有一个声明式基类News
:
class News(Base):
__tablename__ = "news"
id = Column(Integer, primary_key = True)
title = Column(String)
author = Column(String)
url = Column(String)
comments = Column(Integer)
points = Column(Integer)
label = Column(String)
我还有一个函数f(title)
,该函数获取一个字符串并返回3个字符串变体之一:“ good”,“ maybe”或“ never”。我尝试获取过滤的行:
rows = s.query(News).filter(News.label == None and f(News.title) == 'good').all()
但是程序失败,引发此错误:
raise TypeError("Boolean value of this clause is not defined")
我该如何解决?
问题答案:
问题是这样的:
News.label == None and f(News.title) == 'good'
# ^^^ here
Python不允许覆盖布尔 操作
and
和的行为or
。您可以__bool__
在Python
3和__nonzero__
Python
2中在一定程度上影响它们,但所做的只是定义对象的真实值。
如果有问题的对象没有实现__bool__
并抛出错误,或者实现没有抛出,则由于and的短路特性and``or
,您可能会获得相当神秘的错误:
In [19]: (News.label == 'asdf') and True
Out[19]: <sqlalchemy.sql.elements.BinaryExpression object at 0x7f62c416fa58>
In [24]: (News.label == 'asdf') or True
Out[24]: True
因为
In [26]: bool(News.label == 'asdf')
Out[26]: False
这可能并且将导致以不正确的SQL表达式的形式出现问题:
In [28]: print(News.label == 'asdf' or News.author == 'NOT WHAT YOU EXPECTED')
news.author = :author_1
为了产生布尔SQL表达式要么使用and_()
,or_()
和not_()
SQL表达式的功能,或二进制&
,|
和~
操作者重载:
# Parentheses required due to operator precedence
filter((News.label == None) & (f(News.title) == 'good'))
要么
filter(and_(News.label == None, f(News.title) == 'good'))
或将多个条件传递给对的调用Query.filter()
:
filter(News.label == None, f(News.title) == 'good')
或组合多个呼叫至filter()
:
filter(News.label == None).filter(f(News.title) == 'good')