I have a declarative base class 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)
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 the program fails, raising this error:
raise TypeError("Boolean value of this clause is not defined")
How can I resolve it?
In SQLAlchemy 1.4 and above, this object is used for ORM results returned by Session.execute (), which can yield instances of ORM mapped objects either individually or within tuple-like rows. Note that the Result object does not deduplicate instances or rows automatically as is the case with the legacy Query object.
New in version 1.4: SQLAlchemy now has a transparent query caching system that substantially lowers the Python computational overhead involved in converting SQL statement constructs into SQL strings across both Core and ORM. See the introduction at Transparent SQL Compilation Caching added to All DQL, DML Statements in Core, ORM.
Modern SQLAlchemy usage, especially the ORM, places a heavy stress on working within the context of a transaction at all times; the “implicit execution” concept makes the job of associating statement execution with a particular transaction much more difficult.
method sqlalchemy.engine.Engine.connect(close_with_result=False) ¶ Return a new Connection object. The Connection object is a facade that uses a DBAPI connection internally in order to communicate with the database. This connection is procured from the connection-holding Pool referenced by this Engine.
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, or the implementation had not thrown, 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]: <sqlalchemy.sql.elements.BinaryExpression object at 0x7f62c416fa58> 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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With