Skip to main content
Brave Programmer Logo

BraveProgrammer

BraveProgrammer

HomeProjectsBlogsCoursesLessonsAbout

Site footer

BraveProgrammer

Free coding courses, practical tutorials, and real projects from BraveProgrammer. Learn web development with React, Next.js, and TypeScript.

Navigation

  • Home
  • Projects
  • Blogs
  • Courses

Resources

  • About
  • Lessons

© 2026 BraveProgrammer. All rights reserved.

  1. Courses
  2. /
  3. Python Fundamentals

Lesson 51 of 55 · Python

Project: Building a Todo App

Duration: 30 minutes

Project: Building a Todo App\n\nIn this capstone project you’ll combine many of the concepts you’ve learned: Flask routes, SQLite persistence, HTML templating with Jinja2, and basic CRUD operations.\n\n## Steps Overview\n1. Initialize the Flask app and configure a SQLite database.\n2. Create a tasks table with columns id (INTEGER PK) and description (TEXT).\n3. Define routes to list tasks, add a new task, and delete a task.\n4. Render the UI using a simple Jinja2 template (templates/index.html).\n5. (Optional) Add a bit of CSS for a cleaner look.\n\n## Starter Skeleton\npython\nfrom flask import Flask, render_template, request, redirect, url_for\nimport sqlite3\n\napp = Flask(__name__)\n\ndef get_db():\n conn = sqlite3.connect('todo.db')\n conn.row_factory = sqlite3.Row # Access columns by name\n return conn\n\n# Initialise the DB (run once)\ndef init_db():\n with get_db() as db:\n db.execute('CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY, description TEXT NOT NULL)')\n\n@app.route('/')\ndef index():\n db = get_db()\n tasks = db.execute('SELECT * FROM tasks').fetchall()\n return render_template('index.html', tasks=tasks)\n\n@app.route('/add', methods=['POST'])\ndef add_task():\n desc = request.form['description']\n if desc:\n db = get_db()\n db.execute('INSERT INTO tasks (description) VALUES (?)', (desc,))\n db.commit()\n return redirect(url_for('index'))\n\n@app.route('/delete/<int:task_id>', methods=['POST'])\ndef delete_task(task_id):\n db = get_db()\n db.execute('DELETE FROM tasks WHERE id = ?', (task_id,))\n db.commit()\n return redirect(url_for('index'))\n\nif __name__ == '__main__':\n init_db()\n app.run(debug=True)\n\n\n## templates/index.html (very simple)\nhtml\n<!doctype html>\n<html lang="en">\n<head>\n <meta charset="utf-8">\n <title>Todo App</title>\n</head>\n<body>\n <h1>My Todo List</h1>\n <form action="{{ url_for('add_task') }}" method="post">\n <input type="text" name="description" placeholder="New task" required>\n <button type="submit">Add</button>\n </form>\n <ul>\n {% for task in tasks %}\n <li>\n {{ task['description'] }}\n <form action="{{ url_for('delete_task', task_id=task['id']) }}" method="post" style="display:inline;">\n <button type="submit">Delete</button>\n </form>\n </li>\n {% else %}\n <li>No tasks yet!</li>\n {% endfor %}\n </ul>\n</body>\n</html>\n\n\nRun the app, open http://127.0.0.1:5000/ in your browser, and start adding and removing tasks. This project ties together Flask routing, SQLite CRUD, Jinja2 templating, and form handling. Happy coding! 🎉\n

Previous: Testing Flask APIsNext: Version Control with Git