简体   繁体   中英

Flask-SQLAlchemy - adding a new column to a query to pass to a template

For a simple library app in Flask with Flask-SQLAlchemy, I have a Book table and a Checkout table:

class Checkout(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    checkout_date = db.Column(db.DateTime, nullable=False, default=func.now())
    return_date = db.Column(db.DateTime)

    book_id = db.Column(db.Integer, db.ForeignKey('book.id'))
    book = db.relationship('Book',
        backref=db.backref('checkout', lazy='dynamic'))

    def __repr__(self):
        return '<Checkout Book ID=%r from %s to %s>' % (self.book.id, self.checkout_date, self.return_date)

I want to keep all checkout records, and I figure the normalized way to do this is to use Checkout.return_date to determine if the book is returned or not. If the return date of any associated Checkout record is null, the Book is still checked out and if it has no null records, the book is "available". (Really it should never have two null return_dates)

The SQL for this view would be:

select book.*, min(checkout.return_date is not null) as available 
from book 
left join checkout 
on book.id = checkout.book_id
group by book.id;

I can't figure out how to do this in SQLAlchemy without copping out and using a raw SQL string:

db.session.query(Book).from_statement('select book.*, min(checkout.return_date is not null) as available from book left join checkout on book.id = checkout.book_id group by book.id').all()

But I can't access spam_book.available : I get the error 'Book' object has no attribute 'available'

Is there a way to add a dynamic, temporary attribute on to a Book to pass to the template? Or is there a better way to go about doing this?

My end goal is to be able to do {% if book.available %} for each book, in the template.

From your description, I understand your Book to Checkout relationship is OneToMany and you are doing:

  • Only one book can be checked out for one record
  • You library could have more than one copies of one book
  • Different copies of one book will have different and unique book_id

Try to add a method for your Book model.

class Book(db.Model):
    # ...something you already have

    def is_available(self):
        return not self.checkout.filter(Checkout.return_date.isnot(None)).scalar()

In the template, just use:

{% if book.is_available %}

should do the trick.

This is not tested as I don't have SQLAlchemy at hand. Please tell me if it does not work.

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