Capstone: A Full CRUD App

A CRUD app is a web application that lets users Create, Read, Update, and Delete records — the four core operations behind nearly every site, from todo lists to blogs to online stores.

Learn Capstone: A Full CRUD App in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this final lesson you'll combine everything from the course — routes, Jinja templates, SQLAlchemy models, and HTML forms — into one complete task-manager application.

Every CRUD app starts with a model — a SQLAlchemy class describing one record. Here a Task has a title and a done flag. The home route reads all tasks and renders them; a form creates new ones.

The last two operations complete CRUD. Update fetches one record by its id and changes a field; Delete fetches a record and removes it. Both finish with db.session.commit() to save the change.

Using db.get_or_404 means a request for a missing id returns a clean 404 instead of crashing. Every change is only permanent after db.session.commit() .

Here is the complete task manager in one file — model, template, and all four CRUD routes woven together. This is the shape of a real Flask app, ready to extend with login and deploy with Gunicorn.

Complete the create and delete routes below. Replace each ___ so tasks are saved and removed correctly.

You forgot db.session.commit() . Adding or changing objects only stages them — committing is what actually writes to the database.

A form is POSTing to a route that only allows GET. Add methods=["POST"] to the route, matching the form's method .

Extend the Task model so each task also stores a priority, and order the list by it.

Congratulations — you've finished the entire Flask course!

You started with a five-line "Hello, Flask!" app and finished by building a complete CRUD application that combines routes, Jinja templates, SQLAlchemy models, and forms. Along the way you added authentication, structured your code with an app factory, wrote tests, and learned to deploy with Gunicorn.

🚀 What's next? Pick a project you care about, rebuild it from scratch, add login, and deploy it to the web. You now have every tool you need — go build something real.

Practice quiz

What does CRUD stand for?

  • Create, Read, Update, Delete
  • Cache, Route, Update, Deploy
  • Connect, Render, Use, Drop
  • Create, Run, Undo, Deploy

Answer: Create, Read, Update, Delete. CRUD is Create, Read, Update, and Delete.

What is a SQLAlchemy model?

  • An HTML template
  • A class describing one database record
  • A route decorator
  • A config setting

Answer: A class describing one database record. A model is a SQLAlchemy class describing one record (one table row).

Which SQLAlchemy call stages a new object for insertion?

  • db.session.commit()
  • db.create(obj)
  • db.session.add(obj)
  • db.insert(obj)

Answer: db.session.add(obj). db.session.add(obj) stages a new object.

What actually writes staged changes to the database?

  • db.session.flush_all()
  • db.save()
  • db.session.push()
  • db.session.commit()

Answer: db.session.commit(). db.session.commit() persists the staged changes.

Which call reads all rows for the Task model?

  • Task.query.all()
  • Task.read_all()
  • db.all(Task)
  • Task.fetch()

Answer: Task.query.all(). Task.query.all() reads every task.

Which call fetches one record or returns a 404 if missing?

  • Task.query.one()
  • db.get_or_404(Task, id)
  • Task.find(id)
  • db.fetch(Task, id)

Answer: db.get_or_404(Task, id). db.get_or_404(Task, id) returns the record or a clean 404.

How do you remove a record?

  • db.remove(obj)
  • obj.delete()
  • db.session.delete(obj)
  • Task.query.drop(obj)

Answer: db.session.delete(obj). db.session.delete(obj) removes the record (then commit).

If a form POSTs to a GET-only route, what error appears?

  • 404 Not Found
  • 401 Unauthorized
  • 500 Internal Server Error
  • 405 Method Not Allowed

Answer: 405 Method Not Allowed. 405 Method Not Allowed means the route doesn't accept POST; add methods=['POST'].

Why do changes vanish or never appear?

  • You forgot db.session.commit()
  • DEBUG was True
  • The model was uppercase
  • You used a Blueprint

Answer: You forgot db.session.commit(). Without commit(), staged changes are never written to the database.

How does data flow in a typical CRUD request?

  • Template writes directly to the DB
  • The browser queries SQLAlchemy
  • A route reads/writes via SQLAlchemy, then renders a template
  • Forms bypass routes

Answer: A route reads/writes via SQLAlchemy, then renders a template. A route uses SQLAlchemy to read/change data, then renders a template; forms POST back to routes.