Handling Forms in Flask
Read, validate, and never trust user input
In this lesson
An HTML form is how visitors send data to your site — a new note, a search, a sign-up — and Flask hands you the submitted values in request.form. This lesson covers reading that input and, just as importantly, validating it before you trust it.
Explain it like I’m 5
A form is a little mail-in card from the browser to your Python app. Each field has a name, and your app reads the answers by those names.
Forms send named fields to your app
A form posts its fields to a route. Each <input> has a name, and that name is the key your Flask code uses to read the value. A form that changes data should use method="post", and the route must allow POST.
<form method="post" action="/add">
<input name="note">
<button type="submit">Add</button>
</form>
# app.py
from flask import Flask, request, redirect
app = Flask(__name__)
notes = []
@app.route("/add", methods=["GET", "POST"])
def add():
if request.method == "POST":
notes.append(request.form["note"])
return redirect("/")
return "Send a POST to add a note"
Reading and validating input
request.form behaves like a dictionary of submitted fields, so reading a value is a familiar lookup. But submitted text can be blank, padded with spaces, or junk — so clean and check it before using it.
# request.form behaves like a dict of submitted fields
form = {"note": " Buy milk ", "priority": "high"}
note = form["note"].strip()
if note:
print("Saved:", note)
else:
print("Note was empty - not saved")
Saved: Buy milk
Reject what you shouldn’t save
The most common validation is simply refusing blank input.
A form submitted a task field. Read it, strip the whitespace, and print "Added: <task>" only if it isn't blank — otherwise print "Rejected blank task".
form = {"task": " "} # imagine the user submitted only spaces
task = "" # TODO: read form["task"] and strip it
# TODO: print "Added: <task>" if task is non-empty, else "Rejected blank task"
form["task"].strip() removes the spaces; a string of only spaces becomes "", which is falsy, so the else branch runs.
form = {"task": " "}
task = form["task"].strip()
if task:
print("Added:", task)
else:
print("Rejected blank task")
Rejected blank task
Common mistake: Forgetting methods=["GET", "POST"]
Routes accept only GET by default, so a form POST seems to break for no reason.
Add methods=["GET", "POST"] to the route that receives the form, or the submission returns a 405 Method Not Allowed.
Common mistake: Reading the wrong input name
The form’s name and the key in request.form must match exactly, and typos slip in.
Keep the <input name="..."> and request.form["..."] spelled identically. Using request.form.get("note", "") avoids a crash when it’s missing.
Common mistake: Trusting blank or messy input
It works when you type a tidy value, so validation feels optional.
Strip and validate every field. Reject empty values, and treat all submitted data as untrusted until you’ve checked it.
Where does Flask put submitted form values?
request.form is a dict-like object keyed by the name of each input.
Why must you validate user input?
Users can send anything; cleaning and checking input protects your app and your data.
What’s different about a POST request compared to a GET?
GET retrieves; POST submits data meant to create or change something on the server.
Mini exercise (medium)
Write add_note(notes, form) that reads form["note"], strips it, and appends it to the notes list only when it’s non-blank. Return the list either way.
Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.
def add_note(notes, form):
note = "" # TODO: read form["note"] safely and strip it
# TODO: append to notes only if note is non-blank
return notes
notes = ["First"]
add_note(notes, {"note": " Second "})
add_note(notes, {"note": " "})
print(notes)
Use note = form.get("note", "").strip(), then if note: notes.append(note) before returning notes.
def add_note(notes, form):
note = form.get("note", "").strip()
if note:
notes.append(note)
return notes
notes = ["First"]
add_note(notes, {"note": " Second "})
add_note(notes, {"note": " "})
print(notes)
['First', 'Second']
n = []
add_note(n, {"note": "Hi"})
assert n == ["Hi"], "a real note should be added"
add_note(n, {"note": " "})
assert n == ["Hi"], "a blank/whitespace note must be rejected"
add_note(n, {"note": " Trim me "})
assert n == ["Hi", "Trim me"], "the saved note should be stripped of surrounding spaces"
print("✓ Validated and saved!")