Form Validation
Validation ensures:
- required fields are present
- values match expected patterns (email)
- lengths/ranges are safe
Common validators
WTForms ships many validators:
DataRequired()DataRequired()/InputRequired()InputRequired()Email()Email()Length(min=, max=)Length(min=, max=)NumberRange(min=, max=)NumberRange(min=, max=)Regexp()Regexp()
Example:
python
from wtforms.validators import DataRequired, Length
username = StringField("Username", validators=[DataRequired(), Length(min=3, max=20)])python
from wtforms.validators import DataRequired, Length
username = StringField("Username", validators=[DataRequired(), Length(min=3, max=20)])Validation errors
When validation fails, errors are stored per field:
form.username.errorsform.username.errors
You can show them in templates:
html
{% for error in form.username.errors %}
<p class="error">{{ error }}</p>
{% endfor %}html
{% for error in form.username.errors %}
<p class="error">{{ error }}</p>
{% endfor %}Custom validation
You can add custom validation methods:
python
class RegisterForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()])
def validate_username(self, field):
if " " in field.data:
raise ValidationError("Username cannot contain spaces")python
class RegisterForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()])
def validate_username(self, field):
if " " in field.data:
raise ValidationError("Username cannot contain spaces")Custom validators are great for business rules.
Visualize it
Here’s the Post/Redirect/Get pattern that keeps form submissions safe from accidental resubmission.
flowchart TD
G["GET shows the form"] --> S["User submits (POST)"]
S --> V{"Validate"}
V -->|invalid| RE["Re-render form with errors"]
V -->|valid| SV["Save data"]
SV --> RD["Redirect (GET) to success page"]
🧪 Try It Yourself
Exercise 1 – Create a Flask App
Exercise 2 – Dynamic Route
Exercise 3 – Return JSON
If this helped you, consider buying me a coffee ☕
Buy me a coffeeWas this page helpful?
Let us know how we did
