# Python Flask Forms Reference > Source: This reference covers how to work with forms in Flask, including handling GET and POST requests, using WTForms for form creation and validation, implementing CSRF protection, and managing file uploads. --- ## Overview Flask provides tools for handling web forms through: - The `request` object for accessing submitted form data - **Flask-WTF** and **WTForms** for declarative form creation, validation, and CSRF protection - Jinja2 templates for rendering form HTML - Flash messages for user feedback --- ## Basic Form Handling in Flask ### Handling GET and POST Requests ```python from flask import Flask, render_template, request, redirect, url_for, flash app = Flask(__name__) app.secret_key = 'your-secret-key' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form.get('username') password = request.form.get('password') if username == 'admin' and password == 'secret': flash('Login successful!', 'success') return redirect(url_for('dashboard')) else: flash('Invalid credentials.', 'error') return render_template('login.html') ``` ### The `request.form` Object The `request.form` is an `ImmutableMultiDict` that contains parsed form data from POST and PUT requests. | Method | Description | |--------|-------------| | `request.form['key']` | Access a value; raises `400 Bad Request` if missing | | `request.form.get('key')` | Access a value; returns `None` if missing | | `request.form.get('key', 'default')` | Access a value with a fallback default | | `request.form.getlist('key')` | Returns a list of all values for a key (for multi-select fields) | ### The `request.method` Attribute Used to distinguish between GET (displaying the form) and POST (processing the submission): ```python @app.route('/register', methods=['GET', 'POST']) def register(): if request.method == 'POST': # Process the form submission pass # GET: Display the form return render_template('register.html') ``` --- ## Flask-WTF and WTForms ### Installation ```bash pip install Flask-WTF ``` Flask-WTF is a Flask extension that integrates WTForms. It provides: - CSRF protection out of the box - Integration with Flask's `request` object - Jinja2 template helpers - File upload support ### Configuration ```python from flask import Flask app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' # Required for CSRF app.config['WTF_CSRF_ENABLED'] = True # Enabled by default ``` --- ## Defining Forms with WTForms ### Basic Form Class ```python from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, TextAreaField, SubmitField from wtforms.validators import DataRequired, Email, Length, EqualTo class RegistrationForm(FlaskForm): username = StringField('Username', validators=[ DataRequired(), Length(min=3, max=25) ]) email = StringField('Email', validators=[ DataRequired(), Email() ]) password = PasswordField('Password', validators=[ DataRequired(), Length(min=6) ]) confirm_password = PasswordField('Confirm Password', validators=[ DataRequired(), EqualTo('password', message='Passwords must match.') ]) submit = SubmitField('Register') ``` ### Common Field Types | Field Type | Description | |-----------|-------------| | `StringField` | Single-line text input | | `PasswordField` | Password input (masked characters) | | `TextAreaField` | Multi-line text input | | `IntegerField` | Integer input with built-in type coercion | | `FloatField` | Float input with built-in type coercion | | `BooleanField` | Checkbox (True/False) | | `SelectField` | Dropdown select menu | | `SelectMultipleField` | Multiple-select dropdown | | `RadioField` | Radio button group | | `FileField` | File upload input | | `HiddenField` | Hidden input field | | `SubmitField` | Submit button | | `DateField` | Date picker input | ### Common Validators | Validator | Description | |-----------|-------------| | `DataRequired()` | Field must not be empty | | `Email()` | Must be a valid email format | | `Length(min, max)` | String length must fall within range | | `EqualTo('field')` | Must match another field's value | | `NumberRange(min, max)` | Numeric value must fall within range | | `Regexp(regex)` | Must match the provided regular expression | | `URL()` | Must be a valid URL | | `Optional()` | Field is allowed to be empty | | `InputRequired()` | Raw input data must be present | | `AnyOf(values)` | Must be one of the provided values | | `NoneOf(values)` | Must not be any of the provided values | --- ## Using Forms in Routes ### Route with WTForms ```python @app.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() if form.validate_on_submit(): # form.validate_on_submit() checks: # 1. Is the request method POST? # 2. Does the form pass all validation? # 3. Is the CSRF token valid? username = form.username.data email = form.email.data password = form.password.data # Process the data (e.g., save to database) flash(f'Account created for {username}!', 'success') return redirect(url_for('login')) return render_template('register.html', form=form) ``` ### `validate_on_submit()` Method This method combines two checks: 1. `request.method == 'POST'` -- ensures the form was actually submitted 2. `form.validate()` -- runs all validators on the form fields and checks the CSRF token Returns `True` only if both conditions are met. --- ## Rendering Forms in Templates ### Basic Template Rendering ```html
{{ form.hidden_tag() }}
{{ form.username.label }} {{ form.username(class="form-control", placeholder="Enter username") }} {% for error in form.username.errors %} {{ error }} {% endfor %}
{{ form.email.label }} {{ form.email(class="form-control", placeholder="Enter email") }} {% for error in form.email.errors %} {{ error }} {% endfor %}
{{ form.password.label }} {{ form.password(class="form-control") }} {% for error in form.password.errors %} {{ error }} {% endfor %}
{{ form.confirm_password.label }} {{ form.confirm_password(class="form-control") }} {% for error in form.confirm_password.errors %} {{ error }} {% endfor %}
{{ form.submit(class="btn btn-primary") }}
``` ### Key Template Elements | Element | Purpose | |---------|---------| | `{{ form.hidden_tag() }}` | Renders the hidden CSRF token field | | `{{ form.field.label }}` | Renders the `