Handling Forms

Form handling is the process of accepting data a user types into an HTML form, reading it on the server through request.form , validating it, and responding — the backbone of logins, signups, and search boxes.

Learn Handling Forms in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

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 lesson you'll build a form, process its submission, validate the input, and use the Post/Redirect/Get pattern to avoid duplicate submissions.

An HTML <form> with method="POST" sends its fields to the server when submitted. Each input's name attribute becomes a key in request.form .

The classic pattern is one route that handles both methods: on a GET it renders the empty form, and on a POST it reads the submitted values. The example below shows a contact form and, when posted, returns a message built from the user's name and email.

Never trust user input. Before you store or use form data, check that required fields are present and look reasonable. When validation fails, re-show the form with an error so the user can fix it.

The example below validates a signup: the username must be non-empty and the password at least eight characters. It collects any problems into a list and only "creates" the account when the list is empty.

The bad submission returns 400 with a list of problems, while the valid one returns a welcome message — exactly the guardrails real signups need.

After a successful POST, redirect to another page instead of returning HTML. This is the Post/Redirect/Get pattern: it stops the browser from re-submitting the form if the user refreshes.

Pair it with flash() to show a one-time confirmation message. Because flash stores the message in the session, your app needs a secret_key . The example below redirects home after a successful post and flashes a thank-you.

Complete the login route below. Replace each ___ so it accepts POST, reads the username, and redirects to the dashboard.

Your inputs are missing the name attribute, or the form uses GET. Add name="..." to each input and set method="POST" on the form.

❌ RuntimeError: The session is unavailable / no secret key

flash and sessions need a signing key. Set app.secret_key = "..." once when you create the app.

Build a feedback form that validates input and confirms the submission.

Lesson 8 complete — you can collect real user input!

You built a form, read it through request.form , validated the data, and used Post/Redirect/Get with flash to confirm submissions safely.

🚀 Up next: Sessions & Cookies — remember users across requests and keep them logged in.

Practice quiz

Where do submitted POST form values land in Flask?

  • request.args
  • request.form
  • request.json
  • request.cookies

Answer: request.form. Values from a POSTed HTML form are read from request.form.

What becomes the key for a field in request.form?

  • The input's id attribute
  • The input's type attribute
  • The input's name attribute
  • The input's class attribute

Answer: The input's name attribute. Each input's name attribute becomes a key in request.form.

How do you read a field safely without crashing if it is missing?

request.form.get("x") returns None instead of raising when the field is absent.

Which decorator argument lets one route accept both GET and POST?

methods=["GET", "POST"] tells @app.route to accept both verbs.

How do you detect that a form was submitted (not just shown)?

  • request.is_post
  • request.method == "POST"
  • request.submitted
  • request.posted()

Answer: request.method == "POST". Checking request.method == "POST" distinguishes a submit from a GET render.

What does the Post/Redirect/Get pattern prevent?

  • SQL injection
  • Cross-site scripting
  • Duplicate form submissions on refresh
  • Slow page loads

Answer: Duplicate form submissions on refresh. Redirecting after a POST stops a browser refresh from re-submitting the form.

Which function shows a one-time confirmation message?

  • notify()
  • alert()
  • toast()
  • flash()

Answer: flash(). flash() stores a one-time message retrieved with get_flashed_messages().

Why does flash() require app.secret_key to be set?

  • Because flash stores messages in the session, which is signed
  • Because it encrypts the database
  • Because it disables debug mode
  • Because it sets the port

Answer: Because flash stores messages in the session, which is signed. flash messages live in the session, which Flask signs using secret_key.

After a successful POST, what should the save route return?

  • A 500 error
  • A redirect to another page
  • Raw form HTML again
  • Nothing at all

Answer: A redirect to another page. Returning redirect(url_for(...)) implements Post/Redirect/Get.

What is a sensible status code to return when validation fails?

  • 200 OK
  • 301 Moved
  • 404 Not Found
  • 400 Bad Request

Answer: 400 Bad Request. A failed validation typically returns 400 Bad Request with the errors.