I have a database "News" created via SQLAlchemy:
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)
I also have a function f(title), that gets a string and returns one of 3 variants of strings: 'good', 'maybe' or 'never'. I try to get filtered rows:
rows = s.query(News).filter(News.label == None and f(News.title)=='good').all()
But program fails, raising this error:
raise TypeError("Boolean value of this clause is not defined")
How can I resovle it?
The problem is this:
News.label == None and f(News.title) == 'good' # ^^^ here
Python does not allow overriding the behaviour of boolean operations and
and or
. You can influence them to some extent with __bool__
in Python 3 and __nonzero__
in Python 2, but all that does is that it defines the truth value of your object.
If the objects in question had not implemented __bool__
and thrown the error, you would've gotten possibly rather cryptic errors due to the short-circuiting nature of and
and or
:
In [19]: (News.label == 'asdf') and True Out[19]: In [24]: (News.label == 'asdf') or True Out[24]: True
because
In [26]: bool(News.label == 'asdf') Out[26]: False
This could and would lead to hair pulling in the form of incorrect SQL expressions:
In [28]: print(News.label == 'asdf' or News.author == 'NOT WHAT YOU EXPECTED') news.author = :author_1
To produce boolean SQL expressions either use the and_()
, or_()
, and not_()
sql expression functions, or the binary &
, |
, and ~
operator overloads:
# Parentheses required due to operator precedence filter((News.label == None) & (f(News.title) == 'good'))
or
filter(and_(News.label == None, f(News.title) == 'good'))
or pass multiple criterion to a call to Query.filter()
:
filter(News.label == None, f(News.title) == 'good')
or combine multiple calls to filter()
:
filter(News.label == None).filter(f(News.title) == 'good')