"Using SQLAlchemy, I want to find out how many potatoes are on plots of land where the tending farmer actually likes potatoes."In SQL this query could look something like this:
SELECT plot.potato_count
FROM plot
JOIN farmer ON plot.farmer_id=farmer.id
WHERE farmer.likes_potatoes
That's right, if you don't like potatoes, we don't want to know about your plot's potatoes. 🥔So, how do we do this in SQLAlchemy?
In paradise, we can type this:
result = session.query(Plot).filter(Plot.farmer.likes_potatoes == True)However, this is planet Earth, not paradise1, so we must work with what we have. To that end, here are 3 ways to filter a query by an attribute present in a relationship:
-
The cleanest way
result = session.query(Plot).filter(Plot.farmer.has(likes_potatoes=True)
This uses the has() operator which conveniently abstracts away all of the arduous "join" code. This is one reason why it's nice to have an ORM. - The join and filter way
result = session.query(Plot).join(Plot.farmer).\ filter(Plot.farmer.property.mapper.class_.likes_potatoes == True)This uses the join functionality and directly accesses the likes_potatoes attribute of the farmer linked to the plot. - The join and filter_by way
result = session.query(Plot).filter(Plot.farmer.likes_potatoes == True)
This is very similar to method 2, but it uses filter_by to get a cleaner looking filter statement.
SELECT plot.id AS plot_id, plot.farmer_id AS plot_farmer_id
FROM plot
JOIN farmer ON farmer.id = plot.farmer_id
WHERE farmer.likes_potatoes
Inspiration:
This article Multi-table filters in SQLAlchemy
Key Take-aways:
You can enable SQLAlchemy query logging thusly:
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
This SO question which references the has() documentation.
1: A wise man once said (at the bottom of a comment thread) "SQLAlchemy [is] doing its best to bridge two very different languages [SQL and python]"