简体   繁体   中英

What's going on with SQLAlchemy hybrid_property for booleans?

I setup a mapping...

from datetime import datetime

from sqlalchemy import (
    Column,
    Date,
    DateTime,
    Integer,
    func,
)
from sqlalchemy.ext.hybrid import hybrid_property
from orm.models import Base


class Specification(Base):
    """Specification of how a group of things will happen."""

    __tablename__ = "specifications"

    id = Column(Integer, primary_key=True)
    # other fields omitted ..

    date_range_start = Column(Date, nullable=False)
    date_range_end = Column(Date, nullable=False)

    on_hold_until = Column(DateTime, nullable=True)


    @hybrid_property
    def _utc_now(self):
        return datetime.utcnow()

    @_utc_now.expression
    def _utc_now(self):
        return func.timezone("utc", func.current_timestamp())

    @hybrid_property
    def is_on_hold(self):
        """It is on hold if the date has not passed yet."""
        return self.on_hold_until < self._utc_now

    @hybrid_property
    def is_active(self):
        """Only active within the current date ranges."""
        now = self._utc_now
        return (
            (self.is_on_hold == False)
            & (self.date_range_start <= now)
            & (self.date_range_end >= now)
        )

If I want to query Specifications which are currently active, I get the following valid SQL.

>>> print(session.query(Specification).filter_by(is_active=True))
SELECT <omited> 
FROM specifications 
WHERE ((specifications.on_hold_until < timezone(%(timezone_1)s, CURRENT_TIMESTAMP)) = false 
AND specifications.date_range_start <= timezone(%(timezone_2)s, CURRENT_TIMESTAMP) 
AND specifications.date_range_end >= timezone(%(timezone_2)s, CURRENT_TIMESTAMP)) = true

However if I change the is_on_hold comparison to

    (self.is_on_hold is False)

or even

    (not self.is_on_hold)

I get the following error:

TypeError: unsupported operand type(s) for &: 'bool' and 'BinaryExpression'

What is happening here? And how can I use the "normal" Python expressions like self.is_on_hold instead of self.is_on_hold == True/False all the time?

The short answer: You can't .

To implement this logic SQLAlchemy overloads the operators in question. But not all operators are overloadable like in other languages. As such, only the overloadable operators can be used for these SQLAlchemy expressions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM