Project: Todo Full-Stack App

Introduction

This project combines user accounts and personal todo lists in one Flask app—registration, login, CRUD on todos, and database migrations. It is the track’s full-stack capstone: factory pattern, Flask-Login, Flask-WTF, SQLAlchemy, Migrate, and pytest together.

Prerequisites

Project Goals

  • Users register and log in (hashed passwords)
  • Each user sees only their todos
  • Create, complete, and delete todos
  • WTForms for HTML UI (primary mode)
  • pytest covers auth and todo CRUD

Step 1: Models

app/models.py:

Migrate:

bash
flask db migrate -m "Users and todos"
flask db upgrade

Step 2: Auth Blueprint

Registration and login from Flask-Login chapter—redirect to /todos after login.

login_manager.login_view = "auth.login"

Step 3: Todo Routes

app/todos/routes.py:

Code explanation:

  • filter_by(user_id=current_user.id) prevents accessing other users’ todos
  • first_or_404() returns 404 if id wrong or not owned

Step 4: Todo Form

python
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
 
class TodoForm(FlaskForm):
    title = StringField("New todo", validators=[DataRequired(), Length(max=200)])
    submit = SubmitField("Add")

templates/todos/list.html:

For inline toggle/delete forms without TodoForm, expose csrf_token() in template config or use separate small WTF forms.

Step 5: JSON API Mode (Optional)

Add /api/v1/todos returning JSON for the same queries—reuse logic in a service function get_user_todos(user_id) called from HTML and API routes. Pick one primary UI for the tutorial; JSON is optional stretch.

Step 6: pytest

tests/test_todos.py:

Use auth_client fixture from testing chapter.

Verification Checklist

  • Register → login → see empty todo list
  • Add, toggle, delete todos
  • Logout blocks /todos
  • User A cannot delete User B’s todo (404)
  • Migrations apply cleanly on fresh DB
  • pytest green

FAQ

CSRF on inline delete forms?

Each POST form needs CSRF—hidden_tag() or csrf_token().

Due dates and priorities?

Add columns + migration—good schema exercise.

HTMX instead of full reload?

Replace forms with HTMX hx-post—same routes.

Mobile app?

Expose JSON API + JWT from REST project patterns.

Password reset?

Email token flow—requires Flask-Mail and async queue.

Deploy?

Next chapter—production deployment project.