Joins and Lazy vs Eager Loading
Avoid N+1 queries when traversing relations.
Joins and Lazy vs Eager Loading is a free Flask Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Flask Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Querying Across Tables
Sometimes you filter parents by their children's data. A join lets one query span two related tables at once. 🔀
Write a join
Call join() on a query to pull a related model in, then filter on either side as one combined query.
q = User.query.join(Post).filter(Post.title == "Hi")Filter on the Joined Table
After a join, conditions on the other model are fair game, so you find parents by what their children contain.
active = User.query.join(Post).filter(Post.public).all()Lazy Loading Is Default
By default relationships are lazy: the children load only the moment you actually touch that attribute.
user = User.query.first()
user.postsThe N+1 Problem
Looping over parents and reading children lazily fires one query per parent. This N+1 pattern quietly kills performance. 😬
for u in User.query.all():
print(len(u.posts))Eager Loading Fixes It
Eager loading grabs the related rows up front, so the whole graph loads in just a query or two.
joinedload in One Query
Use joinedload to fetch parents and children together with a single SQL join.
from sqlalchemy.orm import joinedload
User.query.options(joinedload(User.posts)).all()selectinload for Collections
selectinload loads children in a second batched query, which often scales better for one-to-many lists.
from sqlalchemy.orm import selectinload
User.query.options(selectinload(User.posts)).all()Set Strategy on the Model
You can also pick a default with the relationship's lazy option, like select, joined, or selectin.
posts = db.relationship("Post", lazy="selectin")Join Does Not Eager Load
A plain join filters across tables but does not preload the relationship. For that you still add an eager option.
Choose Loading on Purpose
Lazy is fine for one row; reach for eager loading whenever you loop over many parents and read their children.
Quick Check
You loop over 100 users and read each user's posts. What problem can lazy loading cause?
Recap: Joins and Loading
You can now join tables, spot N+1, and fix it with joinedload or selectinload. Efficient relational reads, done! 🏁
Frequently asked questions
Is the “Joins and Lazy vs Eager Loading” lesson free?
Yes — the full text of “Joins and Lazy vs Eager Loading” is free to read here on the web, and the Flask Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Flask Academy course, upgrade to CoddyKit PRO.
What will I learn in “Joins and Lazy vs Eager Loading”?
Avoid N+1 queries when traversing relations. You practise Flask Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Flask Academy?
No prior experience is required. Flask Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Joins and Lazy vs Eager Loading” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Flask Academy lesson?
Yes. Every Flask Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Fetch Rows with query and get
- Filter, Order, and Limit Results
- Define Relationships and Foreign Keys
- Joins and Lazy vs Eager Loading