Skip to content

Custom Validation and Error Handling

Manish Sah edited this page Sep 22, 2020 · 1 revision

Showing error messages to user

Our registration route is operation and creates an user if the form data is valid.But it does not provide any feedback to user when the form is not valid

WTForms also keeps track of the errors when user submits the form. We can use form methods to display such errors. Lets show error for email field. replace the div containing email with this code

           <div class="form-group">
                {{ form.email.label(class="form-control-label") }}
                {% if form.email.errors %}
                    {{ form.email(class="form-control form-control-lg is-invalid") }}
                    <div class="invalid-feedback">
                        {% for error in form.email.errors %}
                        <span>{{ error }}</span>
                        {% endfor %}
                    </div>
                {% else %}
                    {{ form.email(class="form-control form-control-lg") }}
                {% endif %}
            </div>

here,

  • form.errors return list of error associated to email field.
  • we loop through them to show all the errors

We will do the same for rest of the form fields and our register.html will look like

{% extends 'layout.html' %}
{% block content %}
<div class="content-section">
    <form method="POST" action="">
        {{ form.hidden_tag() }}
        <fieldset class="form-group">
            <legend class="border-bottom mb-4">Join Today</legend>
            <div class="form-group">

                {{ form.username.label(class="form-control-label") }}
                {% if form.username.errors %}
                    {{ form.username(class="form-control form-control-lg is-invalid") }}
                    <div class="invalid-feedback">
                        {% for error in form.username.errors %}
                        <span>{{ error }}</span>
                        {% endfor %}
                    </div>
                {% else %}
                    {{ form.username(class="form-control form-control-lg") }}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.email.label(class="form-control-label") }}
                {% if form.email.errors %}
                    {{ form.email(class="form-control form-control-lg is-invalid") }}
                    <div class="invalid-feedback">
                        {% for error in form.email.errors %}
                        <span>{{ error }}</span>
                        {% endfor %}
                    </div>
                {% else %}
                    {{ form.email(class="form-control form-control-lg") }}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password.label(class="form-control-label") }}
                {% if form.password.errors %}
                    {{ form.password(class="form-control form-control-lg is-invalid") }}
                    <div class="invalid-feedback">
                        {% for error in form.password.errors %}
                        <span>{{ error }}</span>
                        {% endfor %}
                    </div>
                {% else %}
                    {{ form.password(class="form-control form-control-lg") }}
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.confirm_password.label(class="form-control-label") }}
                {% if form.confirm_password.errors %}
                    {{ form.confirm_password(class="form-control form-control-lg is-invalid") }}
                    <div class="invalid-feedback">
                        {% for error in form.confirm_password.errors %}
                        <span>{{ error }}</span>
                        {% endfor %}
                    </div>
                {% else %}
                    {{ form.confirm_password(class="form-control form-control-lg") }}
                {% endif %}
            </div>

        </fieldset>
        <div class="form-group">
            {{ form.submit(class="btn btn-outline-info") }}
        </div>

    </form>
</div>
{% endblock content %}

Custom Validations

Our registration is working fine but there is an issue. If the user tries to register twice using same username or email, we are not showing those errors(since username and email are unique for User Model)

let update our RegistrationForm in forms.py as

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, ValidationError, EqualTo
from blog.models import User


class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=30)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('Sign Up')


    def validate_username(self, username):
        user = User.query.filter_by(username=username.data).first()
        if user:
            raise ValidationError('That username is taken. Please choose different one')

    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user:
            raise ValidationError('That email is taken. Please choose different one')

here,

  • we have added an addition validation in confirm password field(as password and confirm password must be same)
  • we have added two new methods:- validate_username and validate_email which checks if the user has already been added in database with the give username or email.
  • these methods are called custom validations

Implementation can be found over this commit

Clone this wiki locally