Web Form with Validation Project (code) in Python

← Back to Projects

Web Form with Validation in Python

About the project: This is a project for a self-contained web form with server-side validation using Python and the Flask framework, along with the Flask-WTF library for simplified form handling.

    This project uses a single file to demonstrate how to:
  • Create a web form with a GET route.
  • Handle form submission and validation with a POST route.
  • Display validation error messages to the user.

To make the project a single file, the HTML template is embedded directly into the Python code as a string.

How to Run the App

  1. Install Libraries: This project requires Flask and Flask-WTF. You'll need to install them first using `pip`.
    
        pip install Flask Flask-WTF
        
    Note: Flask-WTF will automatically install WTForms as a dependency.
  2. Save the Code:Save the code above as a file named `web_form_app.py`.
  3. Run from Terminal: Open your terminal or command prompt, navigate to the directory where you saved the file, and run the script:
    
      python web_form_app.py
      
  4. Access the Form: Open your web browser and go to http://127.0.0.1:5000.
The app will display a registration form. You can test the validation by leaving fields blank, entering an invalid email, or providing a password that doesn't match the confirmation. If the form passes validation, it will display a success message.

Project Level: Intermediate

You can directly copy the below snippet code with the help of green copy button, paste it and run it in any Python editor you have.

Steps: Follow these steps

Step 1: Copy below code using green 'copy' button.

Step 2: Paste the code on your chosen editor.

Step 3: Save the code with filename and .py extention.

Step 4: Run (Press F5 if using python IDLE).




# web_form_app.py

from flask import Flask, render_template_string, request, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, EmailField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, Length

# Initialize the Flask application
app = Flask(__name__)
# A secret key is required for Flask-WTF to protect against CSRF attacks.
# Change this to a random value in a real-world application.
app.config['SECRET_KEY'] = 'your-secret-key-that-should-be-random-and-long'

# --- Define the Web Form ---
# This class defines the fields and validation rules for our registration form.
class RegistrationForm(FlaskForm):
    """
    A simple registration form with fields for a username, email, and password.
    Validators ensure the data is present and correctly formatted.
    """
    username = StringField(
        'Username',
        validators=[DataRequired(), Length(min=4, max=25)]
    )
    email = EmailField(
        'Email',
        validators=[DataRequired(), Email()]
    )
    password = PasswordField(
        'Password',
        validators=[DataRequired(), Length(min=8)]
    )
    confirm_password = PasswordField(
        'Confirm Password',
        validators=[DataRequired(), EqualTo('password')]
    )
    submit = SubmitField('Register')


# --- HTML Template as a Python string ---
# This template is embedded directly in the Python file for simplicity.
# It displays the form and any validation errors.
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Registration Form</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        .container {
            background-color: #fff;
            padding: 20px 40px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            width: 400px;
        }
        h2 {
            text-align: center;
            color: #333;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input[type="text"],
        input[type="email"],
        input[type="password"] {
            width: 100%;
            padding: 10px;
            box-sizing: border-box;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .error {
            color: #d9534f;
            font-size: 0.9em;
            margin-top: 5px;
        }
        input[type="submit"] {
            width: 100%;
            padding: 10px;
            background-color: #5cb85c;
            border: none;
            color: white;
            border-radius: 4px;
            font-size: 16px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        input[type="submit"]:hover {
            background-color: #4cae4c;
        }
        ul {
            list-style-type: none;
            padding: 0;
            margin: 0;
        }
        ul li {
            background-color: #f2dede;
            color: #a94442;
            padding: 10px;
            border: 1px solid #ebccd1;
            border-radius: 4px;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>Register</h2>
        {% with messages = get_flashed_messages() %}
        {% if messages %}
        <ul class=flashes>
            {% for message in messages %}
            <li>{{ message }}</li>
            {% endfor %}
        </ul>
        {% endif %}
        {% endwith %}
        <form method="POST" action="{{ url_for('register') }}" novalidate>
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.username.label }}
                {{ form.username() }}
                {% for error in form.username.errors %}
                <span class="error">{{ error }}</span>
                {% endfor %}
            </div>
            <div class="form-group">
                {{ form.email.label }}
                {{ form.email() }}
                {% for error in form.email.errors %}
                <span class="error">{{ error }}</span>
                {% endfor %}
            </div>
            <div class="form-group">
                {{ form.password.label }}
                {{ form.password() }}
                {% for error in form.password.errors %}
                <span class="error">{{ error }}</span>
                {% endfor %}
            </div>
            <div class="form-group">
                {{ form.confirm_password.label }}
                {{ form.confirm_password() }}
                {% for error in form.confirm_password.errors %}
                <span class="error">{{ error }}</span>
                {% endfor %}
            </div>
            <div class="form-group">
                {{ form.submit() }}
            </div>
        </form>
    </div>
</body>
</html>
"""

# --- Flask Routes ---

@app.route('/', methods=['GET', 'POST'])
def register():
    """
    Handles both GET and POST requests for the registration form.
    - On GET, it displays an empty form.
    - On POST, it validates the form data. If validation fails, it
      re-renders the form with error messages. If successful, it
      shows a success message and redirects.
    """
    form = RegistrationForm()

    if form.validate_on_submit():
        # This block only runs if all form validators pass
        
        # In a real application, you would save the user data to a database here.
        # For this example, we'll just print it to the console.
        print(f"User Registered: Username={form.username.data}, Email={form.email.data}")

        # Show a success message
        flash('Registration successful!', 'success')
        
        # Redirect to the same page to show the success message and clear the form
        return redirect(url_for('register'))

    # Render the form template with the form object
    return render_template_string(HTML_TEMPLATE, form=form)

# --- Run the App ---
if __name__ == '__main__':
    # Setting debug=True automatically reloads the server on code changes
    # This should be set to False in a production environment
    app.run(debug=True, host='0.0.0.0', port=5000)
```



← Back to Projects