Completing the Assignment
You have the concepts. Now apply them. Your starter code has a working display and a stub input form. Your job is two things: build the form in input.html, and complete the POST handler in app.py.
Do not start writing code until you've done Steps 0 and 1. Understanding the working code first is not optional.
Step 0: Study the working display
Run the app and visit /display. You should see a table of pre-loaded tasks from tasks.csv.
Now read app.py carefully. For the /display route, trace the whole flow:
- Where does it open
tasks.csv? - How does
DictReaderturn the file into a list? - How does that list get to
display.html? - What does
display.htmldo withtask.statusin the{% if %}block?
Then look at /display/<project_title>. It's the same template but with a filter. Note that it passes project_title as a second argument to render_template — display.html uses that to change the heading.
Once you can trace the full read path, you understand the shape of the data you need to write.
Step 1: Draw the system
Before you write any code, draw a diagram — on paper or digitally — that shows how the /display page gets built. Trace the full journey from the moment a browser requests /display to the moment it receives a finished HTML page.
Your diagram should include all of these components:
app.py— specifically thedisplayroutetasks.csv— where the data livesrender_template()— the hand-off from Python to HTMLbase.html— the shared page structuredisplay.html— the template that fills it in
Show how they connect in sequence. Label your arrows. This doesn't need to be formal — just clear enough that someone unfamiliar with Flask could follow the data flow.
Step 2: Build the form in input.html
Open templates/input.html. The <datalist> is already there. Build your <form> around it.
Your form needs:
action="/input"andmethod="POST"on the<form>tag- A text input for
project_titlewithlist="project-suggestions"to connect it to the datalist - Text inputs for
titleandnext_steps - A
<textarea>fordescription - A
<select>forstatuswith three<option>values:In Progress,Blocked,Done - A submit button
<form action="/input" method="POST">
<label for="project_title">Project:</label>
<input type="text" name="project_title" id="project_title" list="project-suggestions">
<label for="title">Title:</label>
<input type="text" name="title" id="title">
<label for="description">Description:</label>
<textarea name="description" id="description"></textarea>
<label for="status">Status:</label>
<select name="status" id="status">
<option value="In Progress">In Progress</option>
<option value="Blocked">Blocked</option>
<option value="Done">Done</option>
</select>
<label for="next_steps">Next Steps:</label>
<input type="text" name="next_steps" id="next_steps">
<button type="submit">Save Task</button>
</form>
Test: Visit /input. The form should render with all five fields and the submit button. The project_title field should show autocomplete suggestions from the existing CSV data.
Step 3: Complete the POST handler in app.py
Open app.py. Find the if request.method == "POST": block — it's all TODO comments. Replace the pass with working code:
if request.method == "POST":
project_title = request.form["project_title"]
title = request.form["title"]
description = request.form["description"]
status = request.form["status"]
next_steps = request.form["next_steps"]
with open("tasks.csv", "a", newline="") as f:
fieldnames = ["datetime", "project_title", "title", "description", "status", "next_steps"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writerow({
"datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"project_title": project_title,
"title": title,
"description": description,
"status": status,
"next_steps": next_steps,
})
return redirect(url_for("display"))
Test: Submit a task through your form. You should land on /display and see your new row at the bottom of the table.
Open tasks.csv directly and confirm the row is there. Then restart the server and visit /display again — the row should still be there. That's persistence.
Step 4: Verify the filtered view
On /display, click one of the project name links. You should see only that project's tasks, with a heading showing the project name and a "← All tasks" link.
Try typing your project name directly into the URL bar: /display/Your Project Name (with + for spaces: /display/Your+Project+Name).
Step 5 (Stretch): Required fields and direct URL
Add required to your form inputs:
<input type="text" name="title" id="title" required>
The browser will block submission and show a validation message if that field is empty. No Python needed — this is built into HTML.
Then try navigating directly to /display/Task+Tracker in the URL bar to see the seed data filtered by project. This is the same mechanism that will power any filtered view you build.