Skip to main content
Node.js Basics
CHAPTER 07 Beginner

Handling Forms and User Input

Updated: May 13, 2026
25 min read

# CHAPTER 7

Handling Forms and User Input

1. Introduction

A website without user input is just a digital brochure. Real applications require users to log in, submit comments, and upload data. In web development, this is achieved using HTML Forms. However, taking data from an HTML <form> and securely passing it into Python logic requires understanding how HTTP requests transport data. In this chapter, we will learn how to extract data from the request object, handle GET vs. POST methods elegantly, and securely process user input.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Create an HTML form with the correct action and method attributes.
  • Import and utilize the global request object in Flask.
  • Differentiate between request.args (GET) and request.form (POST).
  • Process form submissions within a View function.
  • Use redirect to prevent duplicate form submissions.

3. Beginner-Friendly Explanation

Imagine a drive-thru window.
  • GET Request: You pull up and say, "Give me the menu." The cashier hands you the blank menu (The HTML Form).
  • POST Request: You fill out the menu with your order, attach your credit card, and hand it back through the window.

In Flask, ONE single window (The View Function) has to handle both interactions. When a car pulls up, the cashier (Python) must ask, "Are you here to GET a blank menu, or are you here to POST a finished order?" Based on the answer, the cashier performs a completely different action.

4. Step 1: Building the HTML Form

Let's build a simple login form. Create templates/login.html:
html
123456789101112131415
{% extends "base.html" %}
{% block content %}
    <h1>Login</h1>
    <!-- The method MUST be POST for sensitive data -->
    <form action="/login" method="POST">
        <!-- The &#039;name' attribute is critical! Python uses this to find the data -->
        <label>Email:</label>
        <input type="text" name="user_email" required>
        
        <label>Password:</label>
        <input type="password" name="user_password" required>
        
        <button type="submit">Login</button>
    </form>
{% endblock %}

5. Step 2: The View Function (GET vs POST)

Now we must configure the route to handle the form. We must explicitly allow the POST method, and we must import the global request object to intercept the incoming data.

In app.py:

python
12345678910111213141516171819202122
# Import request, redirect, and url_for
from flask import Flask, render_template, request, redirect, url_for

app = Flask(__name__)

@app.route(&#039;/login', methods=['GET', 'POST'])
def login():
    # If the user clicked the Submit button...
    if request.method == &#039;POST':
        # Extract the data using the 'name' attributes from the HTML!
        email = request.form.get(&#039;user_email')
        password = request.form.get(&#039;user_password')
        
        # (In a real app, you would check the database here)
        if email == &#039;admin@test.com' and password == 'secret':
            return f"Welcome, {email}!"
        else:
            return "Invalid credentials. Try again."
            
    # If the user just typed the URL in their browser...
    else:
        return render_template(&#039;login.html')

6. Step 3: The Redirect Pattern (PRG)

In Step 2, if the login is successful, we returned a string: return f"Welcome...". This is a terrible practice. If the user refreshes the page, the browser will ask, "Are you sure you want to resubmit the form?" and they might accidentally buy an item twice! This is solved by the Post/Redirect/Get (PRG) pattern. After a successful POST, you should ALWAYS redirect the user to a different GET page.

Updating the logic:

python
123
        if email == &#039;admin@test.com' and password == 'secret':
            # Instead of returning a string, redirect them to the homepage!
            return redirect(url_for(&#039;home'))

7. Step 4: Extracting GET Data (Query Strings)

Sometimes forms use the GET method (like search bars). When you search Google, the URL looks like this: /search?q=flask&sort=newest. The data is attached to the URL, not hidden in the request body.

To extract data from the URL, we use request.args instead of request.form.

python
123456789
# Route: /search
@app.route(&#039;/search')
def search():
    # Extracts the 'q' variable from the URL (?q=flask)
    query = request.args.get(&#039;q')
    
    if query:
        return f"Searching database for: {query}"
    return "Please enter a search term."

8. Backend Workflow: WTForms (Advanced Forms)

Extracting data manually with request.form.get() is fine for tiny projects. However, it lacks validation. What if the user types letters into an "Age" field? What if they leave the email field blank? In professional Flask apps, developers use a popular extension called Flask-WTF. It allows you to define forms as Python Classes, automatically generates the HTML, and handles complex validation (like verifying email formats) securely on the backend. We will cover this advanced extension in Chapter 15.

9. Best Practices

  • Use .get() Instead of Dictionary Keys: Always use request.form.get('email') instead of request.form['email']. If the HTML form is broken and the 'email' field is missing, using dictionary brackets ['email'] will crash the entire server with a KeyError. Using .get() will safely return None without crashing.

10. Common Mistakes

  • Forgetting methods=['GET', 'POST']: The #1 mistake beginners make is writing the HTML <form method="POST">, clicking submit, and seeing a "Method Not Allowed" error. By default, Flask routes only accept GET. You must explicitly add the methods list to the decorator.

11. Exercises

  1. 1. Explain the Post/Redirect/Get (PRG) pattern. Why is it dangerous to simply rendertemplate after successfully processing a POST request (like a credit card charge)?

12. Coding Challenges

  • Challenge: Create a newsletter signup form. Create an HTML file with an input field named email. In app.py, map it to /subscribe accepting GET and POST. If POST, extract the email and return a string thanking them. If GET, display the form.

13. MCQs with Answers

Question 1

In Flask, which property of the global request object contains the data submitted via an HTML form using the POST method?

Question 2

When creating a search bar that appends the search term directly into the URL (e.g., ?search=shoes), which HTTP method should the HTML form use?

14. Interview Questions

  • Q: Contrast request.args and request.form in Flask. Under what HTTP circumstances would you use each?
  • Q: Explain why sensitive data (like passwords) must NEVER be transmitted using an HTML form configured with method="GET".

15. FAQs

Q: Can I handle the GET and POST logic in two separate functions instead of one big if/else block? A: Yes! It is perfectly valid to write @app.route('/login', methods=['GET']) on one function to show the form, and @app.route('/login', methods=['POST']) on a completely separate function to process the data.

16. Summary

In Chapter 7, we achieved bi-directional communication. We built HTML forms and learned the critical distinction between GET and POST methods. By importing Flask's global request object, we successfully extracted hidden form data (request.form) and URL query parameters (request.args). Finally, we implemented the industry-standard Post/Redirect/Get (PRG) pattern to ensure safe, duplicate-free form submissions.

17. Next Chapter Recommendation

We can extract data, but currently, we just return it as a string. Real applications save that data permanently. Proceed to Chapter 8: Working with Databases in Flask.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·