2

I have two models representing movies and their show times. I would like to query for all movies, but their show_times relationship should only contain those show times that are in the future.

class PKMovie(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(255))
    show_times = db.relationship('ShowTime')

class ShowTime(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.Date)
    pk_movie_id = db.Column(db.Integer, db.ForeignKey('pk_movie.id'))

Is it possible to affect the contents of the relationship when querying the parent?

davidism
  • 121,510
  • 29
  • 395
  • 339
Andrii Yurchuk
  • 3,090
  • 6
  • 29
  • 40

1 Answers1

3

A relationship, by default, is a simple equality expression: Parent.id == ForeignKey.id. You cannot change the contents of a relationship at query time*, but you can create another relationship that selects only the items you want.

class PKMovie(db.Model):
    # ...
    future_show_times = db.relationship(
        lambda: ShowTime,
        primaryjoin=lambda: db.and_(
            PKMovie.id == ShowTime.pk_movie_id,
            ShowTime.date >= db.func.current_timestamp()
        ),
        viewonly=True
    )

Accessing an instance's future_show_times will return only the show times that are in the future. You can eager load this relationship during the query so that it doesn't incur an extra database query when accessed.

PKMovie.query.options(db.joinedload(PKMovie.future_show_times)).all()

See the documentation for relationships.


* Technically, you can change the relationship at query time, as demonstrated by this answer. However, I think it's much clearer to explicitly define these other relationships.

Community
  • 1
  • 1
davidism
  • 121,510
  • 29
  • 395
  • 339