# 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
```
### Key Template Elements
| Element | Purpose |
|---------|---------|
| `{{ form.hidden_tag() }}` | Renders the hidden CSRF token field |
| `{{ form.field.label }}` | Renders the `