Flask Forms & WTForms

πŸ“¦ Setup

pip install flask-wtf
app.config["SECRET_KEY"] = "genuinely-random-string"   # required for CSRF

πŸ—οΈ Form class

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length
 
class RegistrationForm(FlaskForm):
    username = StringField("Username", validators=[DataRequired(), Length(min=3, max=20)])
    email = StringField("Email", validators=[DataRequired(), Email()])
    password = PasswordField("Password", validators=[DataRequired(), Length(min=8)])
    submit = SubmitField("Register")

🧾 Field types

StringField, PasswordField, IntegerField, BooleanField,
SelectField(choices=[("us","US"),("in","India")]), TextAreaField, DateField, SubmitField

βœ… Validators

ValidatorChecks
DataRequired()not empty
Email()valid email format
Length(min=, max=)length range
EqualTo("field")matches another field (password confirm)
NumberRange(min=, max=)numeric range
Optional()allow empty

Custom validator: def validate_username(self, field): on the form class, raise ValidationError.

πŸ–ΌοΈ View + template

@app.route("/register", methods=["GET", "POST"])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():         # POST + all validators passed
        return f"Registered {form.username.data}"
    return render_template("register.html", form=form)
<form method="POST">
    {{ form.hidden_tag() }}      {# required β€” renders CSRF token #}
    {{ form.username.label }} {{ form.username() }}
    {% for error in form.username.errors %}<span>{{ error }}</span>{% endfor %}
    {{ form.submit() }}
</form>

Omit form.hidden_tag() β†’ CSRF token missing β†’ submission rejected.

πŸ›‘οΈ CSRF

Automatic. Token embedded via hidden_tag(), verified on submit. Toggle: app.config["WTF_CSRF_ENABLED"] = True (default).

🎯 Reading validated data

if form.validate_on_submit():
    username = form.username.data   # already validated + type-converted

Read via .data after validation, not raw request.form.

πŸ“Ž File field

from flask_wtf.file import FileField, FileAllowed, FileRequired
 
photo = FileField("Photo", validators=[FileRequired(), FileAllowed(["jpg","png"], "Images only")])

See Flask File Uploads & Caching for actually saving the file.

πŸ”— Next

Flask Database Integration (SQLAlchemy) Β· Flask Sessions & Cookies