Project Checkpoint
In Part 2, the same project from Part 1 stays in use, but now you work with its data more directly. This milestone has two steps:
- practice SQL directly against the existing project database
- add one small read-only feature that uses the same database from application code
Recommended timing: complete the chapter-level exercises in this part before treating this project milestone as complete.
Step 1: Direct SQL Practice
By this point, the project should already start, expose /decks, and contain the seeded decks data from the previous part. The goal of Step 1 is to get comfortable inspecting and safely changing that same data directly in SQL.
Complete the following:
- Connect to the project database with the course-approved tool, such as
psqlinside the running environment. - Run at least three single-table
SELECTqueries against project tables. - Insert one temporary row into
decks. - Update that same row.
- Delete that same row.
- Verify each change with follow-up
SELECTqueries and, when useful, by refreshing/decks.
If the project is running through Docker Compose, one typical psql workflow is:
docker compose exec db psql -U postgres -d studytracker
Inside psql, the following commands are useful:
\dtto list tables\d table_nameto describe a table’s columns and keysSELECT * FROM table_nameto read all rows from a tableSELECT * FROM table_name WHERE conditionto read only some rowsINSERT INTO table_name (columns) VALUES (values)to add a new rowUPDATE table_name SET column = value WHERE conditionto change existing rowsDELETE FROM table_name WHERE conditionto remove rows
Try at least the following:
\dt
SELECT * FROM decks ORDER BY name;
INSERT INTO decks (name, description)
VALUES ('Temporary SQL Practice', 'Created in Part 2');
SELECT * FROM decks WHERE name = 'Temporary SQL Practice';
UPDATE decks
SET description = 'Updated in Part 2'
WHERE name = 'Temporary SQL Practice';
SELECT * FROM decks WHERE name = 'Temporary SQL Practice';
DELETE FROM decks
WHERE name = 'Temporary SQL Practice';
SELECT * FROM decks WHERE name = 'Temporary SQL Practice';
This is intentionally repetitive. The point is to build the habit of checking the database state after every write.
Submit this small check after you have completed Step 1:
Step 2: Add a Small Read-Only Feature
Step 2 moves the same SQL ideas into the application. The task is deliberately small: one table, one query, one page. The route and template structure are given below; the main missing piece is the SQL query.
Add this near the existing routes in app/main.py:
@app.get("/decks/newest")
def newest_deck(request: Request):
with get_connection() as conn:
deck = conn.execute(
"""
-- TODO: return id, name, description for the newest deck
"""
).fetchone()
return render(request, "newest_deck.html", deck=deck)
Add this template as app/templates/newest_deck.html:
<!doctype html>
<html lang="en">
<body>
<h1>Newest Deck</h1>
{% if deck %}
<p><strong>{{ deck.name }}</strong></p>
{% if deck.description %}
<p>{{ deck.description }}</p>
{% endif %}
{% else %}
<p>No decks found.</p>
{% endif %}
</body>
</html>
Fill in the missing SQL so that it should:
- read from the existing
deckstable, - return
id,name, anddescriptionfor one deck, - order the rows so that the newest deck comes first,
- and limit the result to one row
Once ready, check that the new route works and shows the expected deck.
- Start the project with
docker compose up --build. If the project was already running, stop it and restart with the--buildflag to ensure that the new code is included. - Confirm that
/decksstill works. - Open
/decks/newestand check which deck appears. - Login to the database and insert a new deck (allow PostgreSQL to generate the
id, i.e., do not explicitly specify it). - Refresh
/decks/newestand confirm that it now shows the new deck.
Step 2 is complete when:
/decks/newestloads successfully,- the page reads from the existing
deckstable, - the page shows the newest deck’s
nameanddescription, - and the query uses ordering plus limiting to select that one row
Return the Project
When both steps are complete, return a zip of the project checkpoint. The root of the zip should contain:
requirements.txt- the folder
app - the folder
migrations
You may also include compose.yaml, Dockerfile, and start.sh. These files are useful for local development, but the automated grader focuses on the Python application and the SQL migrations.