0

I'm using a hybrid_property to generate a calculated property that indicates if an article is published based on its scheduled publish date and whether or not it "is_published":

class Article(db.Model):
    __tablename__ = 'articles'
    id = db.Column(db.Integer, primary_key=True)
    publish_date = db.Column(db.DateTime, index=True)
    is_published = db.Column(db.Boolean,index=True,default=False)

    def __repr__(self):
        return '<Article {}>'.format(self.id)

    @hybrid_property
    def published(self):
        """Returns true if the publish date is at or before the current time and is_published is true."""
        return self.is_published and self.publish_date <= datetime.now()

Given the following set of articles:

Article 1: Publish date: 2020-5-12 is_published: True

Article 2: Publish date: 2020-5-13 is_published: False

I can perform the following check:

>>> Article.query.all()[0].published
True
>>> Article.query.all()[1].published
False

But when querying, the filter returns as if the value were true for this calculated field for all articles:

>>> Article.query.filter_by(published=False).all()
[]
>>> Article.query.filter_by(published=True).all()
[<Article 1>, <Article 2>]

Am I doing something wrong? Is there a better way to quickly and easily filter by this basic calculation?

David Scott
  • 796
  • 2
  • 5
  • 22
  • You're running into this: https://stackoverflow.com/questions/42681231/sqlalchemy-unexpected-results-when-using-and-and-or – Ilja Everilä May 30 '20 at 12:07
  • @IljaEverilä, I'm not sure I follow... I'm not getting an error when filtering, only incorrect results, and the property appears to be returning the correct boolean value? Could you explain with more detail how this is relevant? – David Scott May 30 '20 at 12:18
  • 1
    When `self.is_published and self.publish_date <= datetime.now()` is evaluated in query context the resulting query is not what you'd expect, even if no error was raised. It will be either `self.is_published` or `self.publish_date <= datetime.now()` expression, due to the short circuiting nature of `and` in Python. Looks like you're getting the latter. – Ilja Everilä May 30 '20 at 13:13
  • Oh, I see! Okay, so I see how I can resolve this in the query, I could just very easily do .filter(Article.publish_date <= datetime.utcnow() | Article.is_published==False), which is working for me, but is there any way to push this logic into the hybrid property to reduce the complexity of filtering? – David Scott May 30 '20 at 13:25
  • 1
    There is: https://docs.sqlalchemy.org/en/13/orm/extensions/hybrid.html#defining-expression-behavior-distinct-from-attribute-behavior, define the expression to use in query context explicitly. – Ilja Everilä May 30 '20 at 14:05

0 Answers0