【问题标题】:SQLAlchemy: unexpected results when using `and` and `or`SQLAlchemy:使用“and”和“or”时出现意外结果
【发布时间】:2017-07-29 14:31:26
【问题描述】:

我有一个声明性基类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")

我该如何解决?

【问题讨论】:

  • @IljaEverilä 你应该把它作为答案发布,我几乎错过了你的评论,并且已经在写同样的东西了。
  • 我试图为此找到一个现有的副本,但令人惊讶的是找不到。

标签: python sqlalchemy boolean


【解决方案1】:

问题是这样的:

News.label == None and f(News.title) == 'good'
#                  ^^^ here

Python 不允许覆盖布尔操作 andor 的行为。你可以在某种程度上使用 Python 3 中的 __bool__ 和 Python 2 中的 __nonzero__ 来影响它们,但它所做的只是defines the truth value of your object

如果有问题的对象没有实现__bool__ 并抛出错误,或者没有抛出实现,那么由于short-circuiting nature of 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 表达式函数,或二进制 &amp;|~ 运算符重载:

# 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')

【讨论】:

  • 非常详尽,谢谢。是否知道这些方法中的一种是否更可取或性能更好?我有点喜欢只调用 .filter() 两次,因为它非常易读,并且可以将每个语句放在换行符上
  • 我想性能差异可以忽略不计,因为对 filter() 的调用只是将新标准附加到 Query - 它编译为 SQL 并仅在您调用 all() 等时发出. 所以选择最适合你的方法吧。
猜你喜欢
  • 2020-06-05
  • 2013-11-07
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多