6.7. Forms (POST)#
In this section, we’ll learn how to make HTML forms used to POST data and how Flask handles form submissions using the POST method. We’ll also cover how to handle file uploads.
Forms are commonly used for:
Login and registration pages
Adding or updating data (e.g., reviews, blog posts, comments)
Everyday examples of forms include search bars on websites, comment sections on blog posts, and user registration pages.
POST
: Sends data in the body of the request (invisible to users), used for submitting large amounts of data like form submissions or file uploads.
6.7.1. Form Example#
Here’s a HTML form that collects a user’s name and email:
<!DOCTYPE html>
<html>
<head>
<title>Simple Form</title>
</head>
<body>
<h1>Contact Form</h1>
<form action="/submit" method="POST">
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br><br>
<label for="email">Email:</label>
<input type="email" id="email" name="email"><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Explanation
Form Element
<form action="/submit" method="POST">
creates a form that submits data to the/submit
URL using the POST method.
Input Fields
<input type="text" id="name" name="name">
creates a text input for the user’s name.<input type="email" id="email" name="email">
creates an email input.
Submit Button
<input type="submit" value="Submit">
creates a button to send the form data to the server when clicked.
6.7.2. Handling Form Data#
Here’s how to handle the form data in Flask:
from flask import Flask, request
app = Flask(__name__)
@app.route('/submit', methods=['POST'])
def submit_form():
name = request.form['name']
email = request.form['email']
return f"Name: {name}, Email: {email}"
app.run(debug=True), port=5000)
Explanation
Route Definition
The route
/submit
listens for POST requests. We specify this withmethods=['POST']
so Flask knows this endpoint will handle form submissions.
Accessing Form Data
request.form['name']
andrequest.form['email']
access the submitted form data. Therequest.form
dictionary contains the data sent by the form.
Returning a Response
The form data is displayed back to the user by returning a string with the name and email values.
6.7.3. Example: New Movie Review#
Let’s build a form for adding a new movie review to our “Movie Reviews” website. We’ll create a form page to submit data such as the movie title, release year, genre, review score, and review text. The review date will be automatically set.
Importantly we will need two route functions in our Flask app for the form:
the first to return the form HTML
the second to process the form data
Project structure:
├── app.py
├── movies.db
└── templates/
└── index.html
└── new_review.html
1from flask import Flask, request, redirect, url_for
2from sqlalchemy import create_engine, text
3from datetime import datetime
4
5app = Flask(__name__)
6
7# Connect to the database
8engine = create_engine('sqlite:///movies.db')
9
10@app.route('/add_review', methods=['GET'])
11def show_form():
12 return render_template('add_review.html')
13
14@app.route('/add_review', methods=['POST'])
15def add_review():
16 # Get data from the form
17 title = request.form['title']
18 release_year = request.form['release_year']
19 genre = request.form['genre']
20 review_score = request.form['review_score']
21 review_text = request.form['review_text']
22
23 review_date = datetime.now().strftime("%Y-%m-%d")
24
25 # Insert the review into the "database"
26 insert_statement = f'''
27 INSERT INTO reviews (title, release_year, genre, review_date, review_score, review_text)
28 VALUES ('{}', {}, '{}', {}, {}, '{}');
29 '''.format(title, release_year, genre, review_date, review_score, review_text)
30
31 # Execute the SQL query
32 connection.execute(text(insert_statement))
33
34 # Redirect to the form page
35 return redirect(url_for('add_review'))
36
37app.run(debug=True, port=5000)
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>Add Movie Review</title>
5 </head>
6 <body>
7 <h1>Add a New Movie Review</h1>
8 <form action="/add_review" method="POST">
9 <label for="title">Movie Title:</label>
10 <input type="text" id="title" name="title"><br><br>
11
12 <label for="release_year">Release Year:</label>
13 <input type="number" id="release_year" name="release_year"><br><br>
14
15 <label for="genre">Genre:</label>
16 <input type="text" id="genre" name="genre"><br><br>
17
18 <label for="review_score">Review Score (1-10):</label>
19 <input type="number" id="review_score" name="review_score"><br><br>
20
21 <label for="review_text">Review Text:</label><br>
22 <textarea id="review_text" name="review_text"></textarea><br><br>
23
24 <input type="submit" value="Submit Review">
25 </form>
26 </body>
27</html>
Explanation
HTML Form
The form collects details like the movie title, release year, genre, score, and review text.
When the form is submitted, it sends a POST request to
/add_review
.
Flask Handling
The
add_review()
function receives the form data, extracts it usingrequest.form
, and adds the review to database.
Redirecting
After the review is added, the user is redirected back to the form page to indicate success.
6.7.4. HTML Forms - Uploading Files#
Here’s an example of an HTML form that allows users to upload files:
<form action="/upload" method="POST" enctype="multipart/form-data">
<label for="file">Choose a file:</label>
<input type="file" id="file" name="file">
<input type="submit" value="Upload">
</form>
Explanation:
The
enctype="multipart/form-data"
attribute is required for forms that handle file uploads.The
<input type="file">
element allows the user to choose a file to upload.
6.7.5. Handling File Data#
When a file is uploaded, Flask uses the request.files
dictionary to access
the file. Flask also allows you to save the file to the server.
from flask import Flask, request
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return "No file part"
file = request.files['file']
if file.filename == '':
return "No selected file"
# Save the file to the uploads directory
file.save(f'uploads/{file.filename}')
return f"File {file.filename} uploaded successfully!"
app.run(debug=True, port=5000)
Explanation
request.files['file']
retrieves the uploaded file.file.save()
saves the file to a specified directory on the server.
6.7.6. Example: Image Uploads#
To allow users to upload an image along with their movie review, we need to modify both the form and the Flask code.
Project structure:
├── app.py
├── movies.db
└── templates/
└── index.html
└── new_review.html
└── uploads/
1from flask import Flask, request, redirect, url_for
2from sqlalchemy import create_engine, text
3from datetime import datetime
4import os
5
6app = Flask(__name__)
7
8UPLOAD_FOLDER = 'uploads/'
9app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
10
11movie_reviews = []
12
13@app.route('/add_review', methods=['POST'])
14def add_review():
15 # Get form data
16 title = request.form['title']
17 release_year = request.form['release_year']
18 genre = request.form['genre']
19 review_score = request.form['review_score']
20 review_text = request.form['review_text']
21
22 review_date = datetime.now().strftime("%Y-%m-%d")
23
24 # Handle file upload
25 if 'image' in request.files:
26 image = request.files['image']
27 if image.filename != '':
28 image_path = os.path.join(app.config['UPLOAD_FOLDER'], image.filename)
29 image.save(image_path)
30 else:
31 image_path = None
32 else:
33 image_path = None
34
35 # Insert the review into the "database"
36 insert_statement = f'''
37 INSERT INTO reviews (title, release_year, genre, review_date, review_score, review_text, image_path)
38 VALUES ('{}', {}, '{}', {}, {}, '{}', '{}');
39 '''.format(title, release_year, genre, review_date, review_score, review_text, image_path)
40
41 # Execute the SQL query
42 connection.execute(text(insert_statement))
43
44 return redirect(url_for('add_review'))
45
46
47@app.route('/add_review', methods=['GET'])
48def show_form():
49 return render_template('add_review.html')
50
51app.run(debug=True, port=5000)
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>Add Movie Review</title>
5 </head>
6 <body>
7 <h1>Add a New Movie Review</h1>
8 <form action="/add_review" method="POST" enctype="multipart/form-data">
9 <label for="title">Movie Title:</label>
10 <input type="text" id="title" name="title"><br><br>
11
12 <label for="release_year">Release Year:</label>
13 <input type="number" id="release_year" name="release_year"><br><br>
14
15 <label for="genre">Genre:</label>
16 <input type="text" id="genre" name="genre"><br><br>
17
18 <label for="review_score">Review Score (1-10):</label>
19 <input type="number" id="review_score" name="review_score"><br><br>
20
21 <label for="review_text">Review Text:</label><br>
22 <textarea id="review_text" name="review_text"></textarea><br><br>
23
24 <!-- New file upload field -->
25 <label for="image">Upload Poster Image:</label>
26 <input type="file" id="image" name="image"><br><br>
27
28 <input type="submit" value="Submit Review">
29 </form>
30 </body>
31</html>
Explanation
The form now includes a file input field for uploading a movie poster.
The
add_review()
function checks for the image, saves it in theuploads/
folder, and stores the file path in the review data.
To store the image path in the database, the reviews
table should have an additional
column, which can be achieved with the following SQL:
ALTER TABLE reviews ADD COLUMN poster_image_path TEXT;
You can download a version of the database with this change
movies.db
.