Reputation: 380
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.
Upvotes: 0
Views: 1559
Reputation: 611
From your description, I understand your Book
to Checkout
relationship is OneToMany and you are doing:
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.
Upvotes: 1