Monthly Spending Summary
Replace the Python loop in GET /summary with func.sum and group_by
Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.
Why the loop is a problem
The current spending_summary loads every expense row from the database, then adds up totals in Python. For 10,000 expenses across 5 categories, it transfers 10,000 rows to produce 5 numbers.
A GROUP BY query does the same work inside the database and transfers only the 5 results:
results = session.exec(
select(Expense.category, func.sum(Expense.amount)).group_by(Expense.category)
).all()
return {category: total for category, total in results}func.sum(Expense.amount)— applies the SQLSUMfunction to theamountcolumn within each group.funccomes from SQLAlchemy and gives you access to any SQL function by name..group_by(Expense.category)— groups rows bycategorybefore applyingSUM. Each category gets its own total.session.exec(...).all()— returns a list of tuples, one per category:[("food", 42.50), ("transport", 12.00), ...].{category: total for category, total in results}— unpacks each tuple into a dict entry.
func is imported from sqlalchemy, not from sqlmodel. SQLModel builds on SQLAlchemy and exposes its query API, but some lower-level tools like func come directly from SQLAlchemy.
Instructions
Rewrite spending_summary to use SQL aggregation.
- Add
from sqlalchemy import funcas a new import line. - Inside
spending_summary, replace the existing loop with aresultsvariable. Set it tosession.exec(select(Expense.category, func.sum(Expense.amount)).group_by(Expense.category)).all(). - Return
{category: total for category, total in results}.
Interactive Code Editor
Sign in to write and run code, track your progress, and unlock all chapters.
Sign In to Start Coding