Popular Searches
Popular Course Categories
Popular Courses

Handling HTML Forms and User Input

Handling HTML Forms and User Input

Web Development with Python

Handling HTML Forms and User Input in Python

Course: Python Training

Topic: Handling HTML Forms and User Input

Course Link: Python Training Course at JustAcademy

Demo Link: Register for a Course Demo

Website: Visit JustAcademy


1. Introduction to HTML Forms and User Input

HTML forms are an essential part of interactive web applications. They allow users to enter information and submit it to a server for processing. Common examples include login forms, registration forms, contact forms, search boxes, feedback forms, and online application forms.

Python can process submitted form data using web frameworks such as Flask and Django. In a Flask application, the server receives form submissions through the request object, validates the submitted values, performs the required operations, and returns an appropriate response.

Examples of HTML Forms

  • Login form: Collects a username or email address and password.
  • Registration form: Collects details such as name, email, and account information.
  • Contact form: Collects a user's name, email, subject, and message.
  • Search form: Accepts keywords to search for products, articles, or records.
  • Feedback form: Collects ratings, comments, and suggestions.
  • File upload form: Allows users to submit documents or images.

Learning Objectives

  • Understand HTML form elements and their attributes.
  • Learn how form data is submitted through HTTP requests.
  • Understand the difference between GET and POST methods.
  • Process submitted data using Python and Flask.
  • Validate user input on the server side.
  • Display success messages and validation errors.
  • Handle file uploads safely.
  • Apply security practices to protect web applications.

2. Understanding the HTML Form Element

The HTML <form> element groups input controls and defines how the browser submits their values to a server.

Basic HTML Form Example

<form action="/submit" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="username" required>

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>

    <button type="submit">Submit</button>
</form>

Explanation of Form Attributes

Attribute Purpose Example
action Specifies the URL that receives the submitted form. action="/submit"
method Specifies the HTTP method used for submission. method="post"
name Provides the key used to identify a submitted field. name="username"
id Identifies an element within the HTML document. id="username"
required Requires the user to provide a value before submission. required
type Defines the kind of input control. type="email"
enctype Defines how the form body is encoded. multipart/form-data

Important: The name attribute is particularly important because it becomes the key through which the server accesses submitted form data. An input without a name is generally not included as a successful form field in a normal browser submission.

3. Common HTML Input Types

HTML provides different input types for collecting different kinds of information. Choosing an appropriate type improves usability and provides basic browser-side validation.

Input Type Purpose Example
text Accepts short text. Username
email Accepts an email-like value and performs basic browser validation. [email protected]
password Hides entered characters visually. Account password
number Accepts numeric input. Age
tel Accepts a telephone number. Contact number
date Allows selection of a date. Date of birth
radio Allows one selection from a group. Preferred contact method
checkbox Allows an independent selection or multiple selections. Interests
file Allows file selection. Resume upload
hidden Submits a value that is not displayed as a regular input. Form identifier
textarea Accepts multi-line text. Feedback message

Browser-side input types improve the user experience, but they do not replace server-side validation. Users can bypass browser checks by sending a request directly to the server.

4. Understanding GET and POST Methods

HTML forms commonly submit information using the GET or POST HTTP method. The choice depends on the purpose of the form and the nature of the submitted data.

GET Method

The GET method requests a resource. Form values are normally encoded in the URL as query parameters.

<form action="/search" method="get">
    <label for="keyword">Search:</label>
    <input type="text" id="keyword" name="keyword">
    <button type="submit">Search</button>
</form>

A submission might generate a URL such as:

/search?keyword=python

Use GET for:

  • Search forms.
  • Filtering and sorting information.
  • Pagination and other read-only queries.
  • Operations where a shareable or bookmarkable URL is useful.

Do not use GET to submit passwords or perform operations that change server-side data. Query parameters may appear in browser history, logs, and copied URLs.

POST Method

The POST method submits information in the HTTP request body. It is commonly used for registration, contact forms, login submissions, and creating records.

<form action="/register" method="post">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>

    <button type="submit">Register</button>
</form>

Use POST for:

  • Creating new records.
  • Submitting contact or feedback messages.
  • Sending information that should not be placed in the URL.
  • Submitting form data for server-side processing.

POST does not itself encrypt information. Use HTTPS to protect data in transit, and apply appropriate authentication, validation, and security controls.

GET vs POST

Feature GET POST
Typical purpose Retrieve information Submit information or initiate an operation
Data location Usually URL query parameters Usually request body
Bookmarking Often suitable Usually not suitable for repeating a submission
Data visibility Parameters can appear in the URL Body data is not normally displayed in the URL
Security Requires appropriate security measures Also requires HTTPS and appropriate security measures
Typical example Search products Create a customer record

5. Introduction to Flask Form Handling

Flask is a lightweight Python web framework used to build web applications. It provides a request object that lets developers access submitted form values, uploaded files, query parameters, and other request information.

Install Flask

python -m pip install flask

Basic Flask Application

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Welcome to the Flask application!"

if __name__ == "__main__":
    app.run(debug=True)

Save this code in a file named app.py and run it with python app.py. The local development server will display the application address in the terminal.

Debug mode is intended for local development only. Do not expose Flask's development server or interactive debugger in production.

6. Accessing Form Data with Flask

Flask provides the request.form attribute to access form fields submitted through form-encoded requests, such as a typical HTML POST form.

Example: Process a Simple Form

from flask import Flask, request

app = Flask(__name__)

@app.route("/submit", methods=["GET", "POST"])
def submit():
    if request.method == "POST":
        username = request.form.get("username", "").strip()
        return f"Form received for {username}"

    return '''
        <form method="post">
            <label for="username">Username:</label>
            <input type="text" id="username" name="username" required>
            <button type="submit">Submit</button>
        </form>
    '''

if __name__ == "__main__":
    app.run(debug=True)

Explanation

  • request provides information about the current HTTP request.
  • request.method identifies the HTTP method used for the request.
  • request.form contains submitted form fields.
  • request.form.get("username", "") retrieves the username or returns an empty string when the field is missing.
  • strip() removes whitespace from the beginning and end of the submitted value.

Security note: Avoid inserting raw user input directly into HTML responses. Use templates with automatic escaping or explicitly escape untrusted values. The next example uses a Flask template.

7. Using Separate HTML Templates

Writing large HTML documents directly inside Python strings can make an application difficult to maintain. Flask supports the Jinja template engine, allowing HTML files to be stored separately from Python code.

Recommended Project Structure

form_project/
│
├── app.py
└── templates/
    ├── form.html
    └── result.html

Step 1: Create form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contact Form</title>
</head>
<body>
    <h1>Contact Us</h1>

    <form action="/contact" method="post">
        <label for="name">Name:</label>
        <input type="text" id="name" name="name" required>

        <label for="email">Email:</label>
        <input type="email" id="email" name="email" required>

        <label for="message">Message:</label>
        <textarea id="message" name="message" required></textarea>

        <button type="submit">Send Message</button>
    </form>
</body>
</html>

Step 2: Create app.py

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/contact", methods=["GET", "POST"])
def contact():
    if request.method == "POST":
        name = request.form.get("name", "").strip()
        email = request.form.get("email", "").strip()
        message = request.form.get("message", "").strip()

        if not name or not email or not message:
            return "All fields are required.", 400

        return render_template(
            "result.html",
            name=name,
            email=email,
            message=message
        )

    return render_template("form.html")

if __name__ == "__main__":
    app.run(debug=True)

Step 3: Create result.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Form Submitted</title>
</head>
<body>
    <h1>Thank You, {{ name }}!</h1>
    <p>Your contact form has been received.</p>
    <p>Email: {{ email }}</p>
    <p>Message: {{ message }}</p>
    <a href="/contact">Return to Contact Form</a>
</body>
</html>

Flask's Jinja templates automatically escape many values when rendering normal HTML templates. This helps reduce cross-site scripting risks, but developers must still avoid marking untrusted values as safe HTML and must apply suitable validation and security controls.

8. Understanding the Flask Request Object

The Flask request object exposes the data and metadata associated with the current HTTP request.

Property Purpose Typical Use
request.method Returns the HTTP method. Check whether the request is GET or POST.
request.form Provides form-encoded body fields. Read submitted text fields.
request.args Provides URL query parameters. Read search keywords and filters.
request.files Provides uploaded files. Handle image or document uploads.
request.get_json() Parses a JSON request body when appropriately formatted. Receive JSON from an API client.
request.headers Provides HTTP request headers. Inspect content type or other request metadata.
request.cookies Provides cookies sent by the client. Read supported cookie values.

Use the correct request attribute for the type of data being submitted. A regular HTML form generally uses request.form, query parameters use request.args, uploaded files use request.files, and JSON API requests can use request.get_json().

9. Reading Query Parameters

Query parameters are values included in the URL after a question mark. They are useful for searches, filtering, sorting, and pagination.

Example URL

/search?keyword=python&category=programming

Flask Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/search")
def search():
    keyword = request.args.get("keyword", "").strip()
    category = request.args.get("category", "all").strip()

    return (
        f"Keyword: {keyword or 'Not provided'}, "
        f"Category: {category or 'all'}"
    )

if __name__ == "__main__":
    app.run(debug=True)

Visit a URL such as http://127.0.0.1:5000/search?keyword=python&category=programming to test the example locally.

Query parameters are user-controlled input. Validate them before using them in database queries, file operations, or other sensitive tasks.

10. Server-Side Input Validation

Input validation checks whether submitted data meets the application's requirements. It is essential because browser-side validation can be bypassed by manually sending HTTP requests.

Common Validation Checks

  • Required fields: Confirm that essential values are present.
  • Length checks: Ensure values do not exceed permitted limits.
  • Type checks: Verify that a value has the expected type.
  • Format checks: Validate formats such as email addresses or dates.
  • Range checks: Ensure numeric values fall within acceptable limits.
  • Allowed values: Verify that a submitted option belongs to an approved set.
  • Business rules: Confirm that the values make sense for the application's purpose.

Example: Validate User Input

from flask import Flask, request, render_template_string

app = Flask(__name__)

FORM_HTML = """
<form method="post">
    <label for="name">Name:</label>
    <input id="name" name="name" required>

    <label for="age">Age:</label>
    <input id="age" name="age" type="number" required>

    <button type="submit">Submit</button>
</form>
"""

@app.route("/validate", methods=["GET", "POST"])
def validate():
    if request.method == "GET":
        return FORM_HTML

    name = request.form.get("name", "").strip()
    age_text = request.form.get("age", "").strip()

    if not name:
        return "Name is required.", 400

    if len(name) > 100:
        return "Name is too long.", 400

    try:
        age = int(age_text)
    except ValueError:
        return "Age must be a whole number.", 400

    if not 1 <= age <= 120:
        return "Age must be between 1 and 120.", 400

    return f"Valid submission received for {name}."

if __name__ == "__main__":
    app.run(debug=True)

This example demonstrates basic validation. In production applications, return user-facing messages through safely rendered templates rather than inserting untrusted values into HTML strings. Use a form validation library when the number of fields and rules grows.

11. Browser-Side Validation vs Server-Side Validation

Feature Browser-Side Validation Server-Side Validation
Where it runs In the user's browser On the application server
Purpose Provides immediate feedback Enforces application rules and protects data integrity
Examples required, minlength, type="email" Python checks, schema validation, business rules
Can be bypassed? Yes It must be implemented and enforced by the server
Recommended use Improve usability Essential for trustworthy processing

Both approaches should be used together. Browser validation helps users correct mistakes quickly, while server validation ensures that the application does not trust arbitrary incoming data.

12. Handling Checkboxes and Multiple Selections

Checkboxes allow users to select one or more options. When multiple checkboxes share the same name, Flask's request.form.getlist() can retrieve all submitted values.

HTML Example

<form method="post" action="/interests">
    <label>
        <input type="checkbox" name="interests" value="Python">
        Python
    </label>

    <label>
        <input type="checkbox" name="interests" value="SQL">
        SQL
    </label>

    <label>
        <input type="checkbox" name="interests" value="Web Development">
        Web Development
    </label>

    <button type="submit">Submit</button>
</form>

Flask Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/interests", methods=["POST"])
def interests():
    allowed = {"Python", "SQL", "Web Development"}

    selected = request.form.getlist("interests")
    valid_selected = [
        item for item in selected if item in allowed
    ]

    return "Selected interests: " + ", ".join(valid_selected)

if __name__ == "__main__":
    app.run(debug=True)

The server checks the submitted options against an approved set. This is important because a user can submit values that were not offered in the HTML form.

13. Handling Dropdowns and Radio Buttons

Dropdown menus and radio buttons are useful when users should choose from a predefined set of options.

HTML Example

<form method="post" action="/course-selection">
    <label for="course">Choose a course:</label>
    <select id="course" name="course" required>
        <option value="">Select a course</option>
        <option value="python">Python</option>
        <option value="sql">SQL</option>
        <option value="power-bi">Power BI</option>
    </select>

    <p>Preferred mode:</p>
    <label>
        <input type="radio" name="mode" value="online" required>
        Online
    </label>

    <label>
        <input type="radio" name="mode" value="classroom">
        Classroom
    </label>

    <button type="submit">Submit</button>
</form>

Flask Processing Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/course-selection", methods=["POST"])
def course_selection():
    course = request.form.get("course", "")
    mode = request.form.get("mode", "")

    allowed_courses = {"python", "sql", "power-bi"}
    allowed_modes = {"online", "classroom"}

    if course not in allowed_courses:
        return "Select a valid course.", 400

    if mode not in allowed_modes:
        return "Select a valid learning mode.", 400

    return f"Course: {course}; Mode: {mode}"

if __name__ == "__main__":
    app.run(debug=True)

Always validate selection values on the server, even when the options are restricted in the HTML page.

14. Handling Empty Fields and Missing Values

A form submission may omit fields or contain empty strings. Missing values and empty values are not always the same, so applications should handle them deliberately.

from flask import Flask, request

app = Flask(__name__)

@app.route("/profile", methods=["POST"])
def profile():
    name = request.form.get("name")
    phone = request.form.get("phone", "")

    if name is None or not name.strip():
        return "Name is required.", 400

    phone = phone.strip()

    if phone and not phone.isdigit():
        return "Phone must contain digits only.", 400

    return "Profile information received."

if __name__ == "__main__":
    app.run(debug=True)

For international phone numbers, digits-only validation may be too restrictive because valid numbers can contain a plus sign, spaces, or separators. Define validation rules based on the application's actual requirements.

15. Handling File Uploads in Flask

HTML forms can allow users to upload documents, images, and other files. A form that uploads files should normally use method="post" and enctype="multipart/form-data".

HTML Upload Form

<form action="/upload" method="post" enctype="multipart/form-data">
    <label for="document">Choose a document:</label>
    <input type="file" id="document" name="document" required>
    <button type="submit">Upload</button>
</form>

Flask File Upload Example

from flask import Flask, request
from werkzeug.utils import secure_filename
from pathlib import Path

app = Flask(__name__)

UPLOAD_FOLDER = Path("uploads")
ALLOWED_EXTENSIONS = {".pdf", ".png", ".jpg", ".jpeg"}

app.config["MAX_CONTENT_LENGTH"] = 5 * 1024 * 1024

UPLOAD_FOLDER.mkdir(exist_ok=True)

@app.route("/upload", methods=["POST"])
def upload():
    uploaded_file = request.files.get("document")

    if uploaded_file is None or not uploaded_file.filename:
        return "Please select a file.", 400

    safe_name = secure_filename(uploaded_file.filename)

    if not safe_name:
        return "Invalid filename.", 400

    extension = Path(safe_name).suffix.lower()

    if extension not in ALLOWED_EXTENSIONS:
        return "Unsupported file extension.", 400

    destination = UPLOAD_FOLDER / safe_name
    uploaded_file.save(destination)

    return "File uploaded successfully."

if __name__ == "__main__":
    app.run(debug=True)

Security considerations: This example demonstrates basic controls but is not a complete production upload system. A secure implementation should also validate file content, consider randomized server-generated filenames, prevent overwrites, restrict access to uploaded files, scan files where appropriate, and store uploads outside publicly executable directories. Filename sanitization and extension checks alone do not guarantee that a file is safe.

16. Processing Form Data and Saving It to a Database

Many web applications store submitted form data in a database. A typical workflow is to receive the form, validate the values, execute a parameterized database query, and return a confirmation.

Example Using SQLite

import sqlite3
from flask import Flask, request

app = Flask(__name__)

def initialize_database():
    with sqlite3.connect("contacts.db") as connection:
        connection.execute("""
            CREATE TABLE IF NOT EXISTS contacts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT NOT NULL,
                message TEXT NOT NULL
            )
        """)

@app.route("/contact", methods=["POST"])
def save_contact():
    name = request.form.get("name", "").strip()
    email = request.form.get("email", "").strip()
    message = request.form.get("message", "").strip()

    if not name or not email or not message:
        return "All fields are required.", 400

    if len(name) > 100 or len(email) > 254 or len(message) > 5000:
        return "One or more fields exceed the allowed length.", 400

    with sqlite3.connect("contacts.db") as connection:
        connection.execute(
            """
            INSERT INTO contacts (name, email, message)
            VALUES (?, ?, ?)
            """,
            (name, email, message)
        )

    return "Contact information saved successfully.", 201

if __name__ == "__main__":
    initialize_database()
    app.run(debug=True)

Explanation

  • The database initialization function creates a contacts table if it does not already exist.
  • The route retrieves the submitted values through request.form.
  • The application checks for empty fields and excessive lengths.
  • The SQL statement uses placeholders and passes values separately to prevent SQL injection through the submitted values.
  • The database connection context manager handles connection cleanup and transaction behavior.
  • The response returns HTTP status code 201 to indicate that a record was created.

This is a learning example. A production contact form should also validate email addresses, apply CSRF protection where relevant, manage spam, handle database errors, and avoid exposing internal exception details.

17. Preventing SQL Injection in Form Processing

SQL injection occurs when untrusted input is improperly combined with SQL commands. If form values are inserted directly into SQL strings, an attacker may manipulate the query.

Unsafe Example

# Do not use this pattern.
username = request.form.get("username", "")
query = "SELECT * FROM users WHERE username = '" + username + "'"

This code directly combines user-controlled input with SQL syntax, creating a risk of SQL injection.

Safe Parameterized Query

import sqlite3

username = "aarav"

with sqlite3.connect("users.db") as connection:
    cursor = connection.execute(
        "SELECT id, username FROM users WHERE username = ?",
        (username,)
    )
    user = cursor.fetchone()

print(user)

Parameterized queries keep SQL commands separate from values. Use the parameter syntax supported by your database driver. Do not rely on string concatenation or formatting to insert user input into SQL statements.

18. CSRF Protection for Forms

Cross-Site Request Forgery (CSRF) is an attack in which a browser can be tricked into sending an unwanted request to a website where the user is already authenticated. State-changing form submissions should be protected when the application's authentication model makes CSRF relevant.

Common Protection Measures

  • Use a trusted CSRF protection library such as Flask-WTF's CSRF support.
  • Include and validate a CSRF token in protected forms.
  • Use secure cookie settings and appropriate SameSite policies.
  • Require authentication and authorization for protected operations.
  • Do not assume that hiding a form field or using POST alone prevents CSRF.

Example with Flask-WTF

python -m pip install flask-wtf
from flask import Flask, render_template_string
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config["SECRET_KEY"] = "replace-with-a-secure-secret"
CSRFProtect(app)

@app.route("/feedback", methods=["GET", "POST"])
def feedback():
    return render_template_string("""
        <form method="post">
            <input name="message" required>
            <input type="hidden" name="csrf_token"
                   value="{{ csrf_token() }}">
            <button type="submit">Send</button>
        </form>
    """)

if __name__ == "__main__":
    app.run(debug=True)

Replace the example secret with a securely generated secret stored outside source control. For larger applications, use Flask-WTF forms or a maintained template integration to manage CSRF tokens consistently. Never deploy with a known placeholder secret.

19. Preventing Cross-Site Scripting (XSS)

Cross-Site Scripting occurs when untrusted data is interpreted as executable content in a browser. Form values must be handled carefully when they are displayed in HTML pages.

Best Practices

  • Render user-submitted values through templates with automatic HTML escaping.
  • Avoid inserting untrusted values directly into HTML strings.
  • Do not mark user-generated content as safe HTML unless it has been appropriately sanitized.
  • Validate input according to the expected business rules.
  • Use a suitable Content Security Policy as an additional layer of protection where appropriate.

Validation and output escaping serve different purposes. Validation checks whether input is acceptable for an application, while escaping helps ensure that output is interpreted in the intended context.

20. Redirecting After Form Submission

After processing a successful POST form, applications often redirect the user to a result page. This pattern is commonly called Post/Redirect/Get (PRG). It helps reduce accidental duplicate submissions when the user refreshes the resulting page.

from flask import Flask, request, redirect, url_for, render_template_string

app = Flask(__name__)

@app.route("/feedback", methods=["GET", "POST"])
def feedback():
    if request.method == "POST":
        message = request.form.get("message", "").strip()

        if not message:
            return "Message is required.", 400

        # Save or process the message here.
        return redirect(url_for("feedback_success"))

    return render_template_string("""
        <form method="post">
            <label for="message">Feedback:</label>
            <textarea id="message" name="message" required></textarea>
            <button type="submit">Submit</button>
        </form>
    """)

@app.route("/feedback-success")
def feedback_success():
    return "Thank you for your feedback!"

if __name__ == "__main__":
    app.run(debug=True)

The example demonstrates the redirect pattern. In an actual application, implement CSRF protection and persist the feedback before redirecting. Redirecting alone does not prevent every duplicate operation, so critical actions may also require idempotency controls.

21. Displaying Validation Errors in Templates

When a form contains invalid data, a helpful application explains what needs to be corrected. Instead of returning a plain error string for every validation failure, render the form again with a message.

Flask Example

from flask import Flask, request, render_template_string

app = Flask(__name__)

FORM_TEMPLATE = """
<h1>Registration Form</h1>
{% if error %}
    <p>{{ error }}</p>
{% endif %}
<form method="post">
    <label for="username">Username:</label>
    <input id="username" name="username"
           value="{{ username }}" required>
    <button type="submit">Register</button>
</form>
"""

@app.route("/register", methods=["GET", "POST"])
def register():
    error = None
    username = ""

    if request.method == "POST":
        username = request.form.get("username", "").strip()

        if not username:
            error = "Please enter a username."
        elif len(username) < 3:
            error = "Username must contain at least 3 characters."
        elif len(username) > 30:
            error = "Username must contain no more than 30 characters."
        else:
            return "Registration details are valid."

    return render_template_string(
        FORM_TEMPLATE,
        error=error,
        username=username
    )

if __name__ == "__main__":
    app.run(debug=True)

Jinja automatically escapes normal template variables by default. Avoid displaying sensitive fields such as passwords again after a validation failure. In production, consider using a dedicated form library to organize field-level errors and validation rules.

22. Common Mistakes When Handling Forms

Mistake Why It Causes Problems Solution
Missing name attributes Expected values may not be included in the submitted form. Add a unique, meaningful name to each input.
Using GET for sensitive data Values may appear in URLs, logs, and browser history. Use POST where appropriate and always use HTTPS for sensitive information.
Ignoring server validation Client-side checks can be bypassed. Validate all important fields on the server.
Accessing missing fields directly Missing keys can cause errors. Use request.form.get() and validate the result.
Trusting dropdown options Users can submit values that were not offered. Validate values against an approved list.
Building SQL with strings Untrusted input can alter SQL commands. Use parameterized queries.
Displaying raw input in HTML Untrusted data may cause XSS. Use safely escaped templates.
Ignoring CSRF Authenticated users may be tricked into unintended actions. Apply CSRF protection to relevant state-changing requests.
Trusting uploaded filenames Filenames can be manipulated and may cause unsafe file handling. Sanitize filenames, validate content, limit size, and control storage.

23. Practical Mini Project: Student Registration Form

Build a simple student registration application that collects a student's name, email, age, and course preference. The application validates the input and displays a confirmation page.

Project Requirements

  • Create an HTML registration form.
  • Collect name, email, age, and course.
  • Use appropriate input types and required attributes.
  • Process the submitted values in Flask.
  • Validate fields on the server side.
  • Display clear validation messages.
  • Use Jinja templates to display the result safely.
  • Optionally store valid submissions in SQLite using parameterized queries.

Suggested Folder Structure

student_registration/
│
├── app.py
└── templates/
    ├── registration.html
    └── success.html

Extension Tasks

  • Prevent duplicate registrations using a database constraint.
  • Add a dropdown for course selection and validate its submitted value.
  • Add CSRF protection.
  • Use a flash message to confirm successful submission.
  • Add unit tests for valid and invalid input.
  • Deploy the application using a production-ready server.

24. Testing Form Handling

Testing ensures that the application processes valid data correctly and rejects invalid submissions. Both successful and unsuccessful cases should be checked.

Test Case Expected Result
Submit all valid required fields. The application processes the form successfully.
Submit an empty required field. The server rejects the submission with a validation message.
Submit an invalid numeric value. The server reports a validation error.
Submit an unexpected dropdown value. The server rejects the unsupported value.
Submit an extremely long message. The server enforces its configured length limit.
Submit malformed or unexpected data. The application handles the request without an unhandled error.
Upload an unsupported file. The application rejects the file.

Basic Flask Test Client Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/subscribe", methods=["POST"])
def subscribe():
    email = request.form.get("email", "").strip()

    if not email or "@" not in email:
        return "Invalid email.", 400

    return "Subscribed successfully.", 200

def test_subscribe_valid_email():
    with app.test_client() as client:
        response = client.post(
            "/subscribe",
            data={"email": "[email protected]"}
        )

        assert response.status_code == 200
        assert b"Subscribed successfully" in response.data

def test_subscribe_invalid_email():
    with app.test_client() as client:
        response = client.post(
            "/subscribe",
            data={"email": "invalid-email"}
        )

        assert response.status_code == 400

These functions illustrate basic assertions with Flask's test client. Run them using a test runner such as pytest after placing the application and tests in appropriate Python files. For production email validation, use a dedicated validation approach instead of relying on a simple @ check.

25. Interview Questions and Answers

Q1. What is an HTML form?

Answer: An HTML form is a collection of input controls that allows users to submit information to a server.

Q2. What is the purpose of the form action attribute?

Answer: The action attribute specifies the URL that receives the submitted form data.

Q3. What is the difference between GET and POST?

Answer: GET is generally used to retrieve information and commonly places parameters in the URL. POST commonly submits data in the request body for processing or creation of resources.

Q4. How does Flask access submitted form values?

Answer: Flask provides request.form for form-encoded fields submitted in the request body.

Q5. What is the purpose of the name attribute?

Answer: The name attribute identifies a form field in the submitted data and is used as the key for accessing its value on the server.

Q6. What is server-side validation?

Answer: Server-side validation checks submitted values on the server before the application processes or stores them.

Q7. Why is client-side validation insufficient?

Answer: Client-side checks can be bypassed. Important validation rules must also be enforced by the server.

Q8. How do you retrieve a query parameter in Flask?

Answer: Use request.args.get("parameter_name") to retrieve a URL query parameter.

Q9. How do you retrieve multiple checkbox values?

Answer: Use request.form.getlist("field_name") when multiple submitted values share the same field name.

Q10. How are files accessed in Flask?

Answer: Uploaded files are accessed through request.files. The HTML form should generally use POST and enctype="multipart/form-data".

Q11. What is CSRF?

Answer: Cross-Site Request Forgery is an attack that can cause a user's browser to submit an unwanted request to a site where the user is authenticated.

Q12. What is SQL injection?

Answer: SQL injection occurs when untrusted input changes the meaning of an SQL statement. Parameterized queries help prevent this issue.

Q13. Why should Jinja templates be used?

Answer: Jinja separates HTML from Python application logic and automatically escapes many variable values in normal HTML templates.

Q14. What is the Post/Redirect/Get pattern?

Answer: It is a workflow in which the server processes a POST request and redirects the browser to a GET page, helping reduce accidental resubmission during refresh.

Q15. Why should form data be validated before saving it to a database?

Answer: Validation helps maintain data quality, enforce business rules, reject unexpected values, and reduce application errors.

26. Quick Revision Checklist

  • Understand the purpose and structure of HTML forms.
  • Know the difference between GET and POST.
  • Use appropriate HTML input types and meaningful name attributes.
  • Access form data through Flask's request.form.
  • Read query parameters through request.args.
  • Use request.files to process uploaded files.
  • Validate all important values on the server.
  • Use templates with automatic escaping to display submitted values.
  • Use parameterized SQL queries for database operations.
  • Protect relevant forms against CSRF.
  • Apply suitable file upload restrictions.
  • Use redirects after successful POST submissions where appropriate.
  • Test valid, invalid, missing, and unexpected input.

27. Conclusion

Handling HTML forms and user input is a fundamental skill for Python web development. HTML forms collect information, HTTP transmits the submitted data, and frameworks such as Flask process the request on the server.

Reliable form handling requires more than reading values. Developers must validate submitted data, handle missing fields, display helpful feedback, use safe database queries, protect relevant forms against CSRF, and escape untrusted output. File uploads require additional controls for filenames, content, storage, and size.

Practise by building a contact form, registration form, and feedback form using Flask. Then extend your projects with database storage, automated tests, authentication, and secure deployment.

28. Additional Learning Resources

whatsapp