Flask-WTForms
WTForms protect Cross-Site Request Forgery Attack by creating random token in every time the browser refresh. And it also supports input validation. It is easy to create form, validation and show error messages.
Quickstart
There is 5 steps to use wtform in flask.
1. Installation
pip install WTForms
pip install Flask-WTF
2. create form
main.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email, Lengthclass LoginForm(FlaskForm):
email = StringField(label='email', validators=[DataRequired()])
password = PasswordField(label='password', validators=[DataRequired()])
3. create secret key
app.config['SECRET_KEY'] = 'secret'
4. passing form
main.py
@app.route("/", methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST':
print(request.form['email'])
print(request.form['password'])
return redirect(url_for("success", email=request.form['email']))
return render_template("login.html", form=form)
login.html
<form method="POST" action="{{url_for('login')}}">
{{ form.csrf_token }}
{{ form.email.label }}
{{ form.email }}<br>
{{ form.password.label }}
{{ form.password }}<br>
<button type="submit">Login</button>
</form>
5. Check csrf_token
main.py
@app.route("/", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
print(request.form['email'])
print(request.form['password'])
return redirect(url_for("success", email=request.form['email']))
return render_template("login.html", form=form)
Create form
Inherit flask wtform when creating our own form and in form class have fields objects and each field create input fields.
main.py
from flask_wtf import FlaskForm
from wtforms import PasswordField
from wtforms.fields.html5 import EmailField
from wtforms.validators import DataRequired, Email, Lengthclass LoginForm(FlaskForm):
email = EmailField(label='email', validators=[DataRequired()])
password = PasswordField(label='password', validators=[DataRequired()])
Csrf_token
There is a hidden input tag with value with csrf_token. That values change when the browser refresh and we only need to check that token in flask application if user actually submit the form.
Check CSRF Token
form.validate_on_submit() function check csrf token. Not only wtform is submitted but also check form validation and csrf token. Submit field never work in wtform until valid csrf token.
@app.route("/", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
print(request.form['email'])
print(request.form['password'])
return redirect(url_for("success", email=request.form['email']))
return render_template("login.html", form=form)
Fields
Field is the type of input in form. In field object you can pass label, validators and other parameters.
- Label ➜ label of the fields
- Validators ➜ validators check input if it is validate. (for example, minium password is 7 characters) wtforms validators
Most useful fields
- password field
- text field
- boolean field
- textarea field
- select field
- radio field
- email field
- file field
- multiple file field
1. Password Field
<input type=”password”>
from wtforms import PasswordFieldpassword = PasswordField(label='password', validators=[DataRequired()])
get password
form.password.data
2. Text Field
<input type=”text”>
from wtforms import TextFieldname = TextField(label='name', validators=[DataRequired()])
get text input data
form.name.data]
3. BooleanField
<input type=”checkbox”>
from wtforms import BooleanFieldagree = BooleanField(label='agree')
get checkbox data
form.agree.data
4. Text area Field
<textarea></textarea>
from wtforms import TextAreaFieldcomment = TextAreaField(label='comment')
get text area input data
form.comment.data
5. Select Field
<select id="colors" name="colors">
<option value="red">red color</option>
<option value="blue">blue color</option>
<option value="yellow">yellow color</option>
</select>
In select field, choices parameter with list to create multiple values.
choices = [(value, label)]
from wtforms import SelectFieldcolors = SelectField(label='color', choices=[('red', 'red color'), ('blue', 'blue color'), ('yellow', 'yellow color')])
get selected data
form.colors.data
6. Radio Field
<input id="genders-0" name="genders" type="radio" value="female">
<label for="genders-0">female</label>
<input id="genders-1" name="genders" type="radio" value="male">
<label for="genders-1">male</label>
In radio field, choices parameter with list to create multiple values.
choices = [(value, label)]
from wtforms import RadioFieldgenders = RadioField(label='gender', choices=[('female', 'female'), ('male', 'male')])
get radio input data
{% for gender in form.genders %}
<tr>
<td>{{ gender }}</td>
<td>{{ gender.label }}</td>
</tr>
{% endfor %}
7. Email Fields
<input type=”email”>
from wtforms.fields.html5 import EmailFieldemail = EmailField(label='email', validators=[DataRequired()])
get email input data
form.email.data
8. File Field
<input id=”logo” name=”logo” type=”file”>
from werkzeug.utils import secure_filename
from flask_wtf.file import FileFieldlogo = FileField(label='logo')
get file data
if form.validate_on_submit():
filename = secure_filename(form.logo.data.filename)
return redirect(url_for("success", email=request.form['email']))
else:
filename = None
set the enctype in html form
<form method="POST" action="{{url_for('login')}}" enctype="multipart/form-data">
9. Multiple File Fields
<input id=”images” multiple=”” name=”images” type=”file”>
from wtforms import PasswordField, MultipleFileFieldimages = MultipleFileField(label='images upload')
get multiple files data
form.images.data
More Fields
Basic Fields [documentation of Basic Fields in WTForms]
HTML5 Fields [documentation of HTML5 Fields in WTForms]
Validators
Validators check input if it is valid. (for example, minium password is 7 characters or data required) wtforms validators
- passing validators as fields parameter
- error messages with flash messages
1. DataRequired
passing validators as fields parameter
from wtforms.validators import DataRequiredemail = EmailField(label='email', validators=[DataRequired()])
2. Email
- passing validators as fields parameter (main.py)
from wtforms.validators import DataRequired, Emailemail = EmailField(label='email', validators=[DataRequired(), Email(message='Invalid Email')])
- errors messages with flash messages (login.html)
{{ form.email.label }}
{{ form.email }}<br>
{% if form.errors %}
<ul class=errors>
{% for error in form.errors['email'] %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
3. Length of string
- passing validators as fields parameter (main.py)
from wtforms.validators import DataRequired, Email, Lengthpassword = PasswordField(label='password', validators=[DataRequired(), Length(min=5, max=20, message="min 5 and max 20")])
- showing validation errors with flash messages (login.html)
{{ form.password.label }}
{{ form.password }}<br>
{% if form.errors %}
<ul class=errors>
{% for error in form.errors['password'] %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
4. File Required
- passing validators as fields parameter (main.py)
from flask_wtf.file import FileField, FileRequiredimage = FileField(label='image upload', validators=[FileRequired()])