CHAPTER 10
Beginner
Building CRUD Applications in Flask
Updated: May 14, 2026
40 min read
# CHAPTER 10
Building CRUD Applications in Flask
1. Introduction
In the previous chapter, we manipulated the database using the terminal shell. However, real users interact with databases through web browsers. In this chapter, we will synthesize routing, Jinja2 templates, HTML forms, and SQLAlchemy to build a complete CRUD (Create, Read, Update, Delete) application. We will build a web interface that allows users to seamlessly manage records in our SQLite database.2. Learning Objectives
By the end of this chapter, you will be able to:- Integrate SQLAlchemy queries directly inside Flask View functions.
- Render dynamic database data to an HTML template (Read).
- Process HTML forms to save new records to the database (Create).
- Query and modify existing records (Update).
- Remove records from the database securely (Delete).
3. Beginner-Friendly Explanation
Think of your web application as a sophisticated filing system.- Create: A user fills out a registration form. The server takes that form and creates a new file folder in the cabinet.
- Read: A user asks to see a list of all employees. The server opens the cabinet, counts all the folders, and writes a list on a whiteboard (The HTML Template).
- Update: An employee gets married and changes their last name. The server finds their specific folder and rewrites the name tag.
- Delete: An employee leaves the company. The server finds their folder and throws it in the shredder.
These four operations (CRUD) form the backbone of 90% of all software engineering.
4. Step 1: READ (Displaying Data)
Let's update our homepage to display all the users currently in the database.In app.py:
python
In templates/home.html:
html
5. Step 2: CREATE (Inserting Data)
We need a web form so visitors can add themselves to the database.In app.py:
python
*(You will need an add_user.html template with a POST form containing name="username" and name="email" inputs).*
6. Step 3: UPDATE (Modifying Data)
To update a specific user, we must pass their ID in the URL, fetch their current data, and overwrite it.In app.py:
python
7. Step 4: DELETE (Removing Data)
To securely delete data, we fetch the specific object and call.delete().
In app.py:
python
8. Backend Workflow: The get_or_404 Method
In Steps 3 and 4, we used User.query.get_or_404(id).
Why didn't we use standard User.query.get(id)?
Because if a malicious hacker tries to visit /delete/999 and user 999 does not exist, standard .get() returns None. When the code tries to delete None, Python crashes the entire server with an AttributeError.
Using .get_or_404() gracefully catches the error and displays a safe "Page Not Found" screen to the hacker, keeping your server online and secure.
9. Best Practices
-
POST for Deletions: In Step 4, we made the delete route a simple GET request. In a professional application, this is a severe security risk. A web crawler (like Googlebot) visiting every link on your site would accidentally click every
/delete/idlink and wipe your entire database! Deletions should ALWAYS be protected behind aPOSTrequest form.
10. Common Mistakes
-
Unique Constraint Failures: In Chapter 9, we set
emailtounique=True. If a user fills out the Create form with an email that already exists in the database,db.session.commit()will crash with anIntegrityError. You must usetry/exceptblocks (Chapter 15) to catch this error and show a polite message to the user ("Email already in use") instead of crashing the server.
11. Exercises
- 1. Explain the chronological flow of data starting from the moment a user clicks a "Delete User" link, to the moment they are redirected back to the homepage.
12. Coding Challenges
-
Challenge: Update your
home.htmltemplate. Inside the loop that displays each user, add two HTML hyperlink tags (<a>). One link should point to{{ url_for('update_user', id=user.id) }}with the text "Edit". The other should point todelete_userwith the text "Delete".
13. MCQs with Answers
Question 1
When building an Update route, why is it unnecessary to call db.session.add(user) before calling db.session.commit()?
Question 2
What is the critical advantage of using User.query.get_or_404(id) instead of standard .get(id) in detail or delete routes?
14. Interview Questions
-
Q: Explain the Post/Redirect/Get (PRG) pattern. Why must a developer return a
redirect()rather thanrender_template()after successfully processing a Create or Update operation?
-
Q: Why is it considered a critical security vulnerability to execute database deletion operations (
db.session.delete) via a standardGETHTTP request?
15. FAQs
Q: My database has 10,000 users. Won'tUser.query.all() crash my server?
A: Yes! Loading 10,000 Python objects into RAM at once will cause massive memory issues. In production, developers use Pagination (e.g., User.query.paginate(page=1, per_page=20)) to only load 20 users at a time.
16. Summary
In Chapter 10, we combined all our backend knowledge to build a fully functional CRUD application. We queried data via SQLAlchemy and rendered it dynamically using Jinja2 templates (Read). We utilized HTML POST forms to extract user input and securely inserted new records (Create). We safely retrieved existing records usingget_or_404 to modify attributes (Update) and remove them entirely (Delete), implementing the PRG pattern to ensure a seamless user experience.