How to override the html default "Please fill out this field" wh

ghz 7months ago ⋅ 119 views

How to override the html default "Please fill out this field" when validation fails in Flask?

I have a Flask-WTF form with with DataRequired validators and related error messages. However, the Chrome browser seems to ignore my error messages and just displays "Please fill out this field". How do I get Flask to override this and show my messages?

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired

class SignupForm(FlaskForm):
    first_name = StringField('First Name', validators=[DataRequired(message='Hey, put in your first name!')])
    last_name = StringField('Last Name', validators=[DataRequired("What, you can't remember your last name?")])
    email = StringField('Email', validators=[DataRequired('Gonna need your email address!')])
    password = PasswordField('Password', validators=[DataRequired('Really need a password, Dude!')])
    submit = SubmitField('Sign Up')

Answers

The issue you're encountering is due to the HTML5 validation that modern browsers, like Chrome, perform by default on form fields with the required attribute. This browser-level validation happens before your form is submitted to the server, thus preventing your custom error messages from being shown.

To make sure that your custom error messages from Flask-WTF are displayed instead of the default browser messages, you need to disable the HTML5 validation on the form. This can be done by setting the novalidate attribute on the <form> tag.

Here's how you can achieve this:

  1. Disable the HTML5 validation in your Flask-WTF form by adding the novalidate attribute to the form.
  2. Ensure you handle the validation on the server side and display the custom error messages in your template.

Below is an example of how you can modify your form template and handle the form in your Flask route.

Flask Form Definition

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired

class SignupForm(FlaskForm):
    first_name = StringField('First Name', validators=[DataRequired(message='Hey, put in your first name!')])
    last_name = StringField('Last Name', validators=[DataRequired(message="What, you can't remember your last name?")])
    email = StringField('Email', validators=[DataRequired(message='Gonna need your email address!')])
    password = PasswordField('Password', validators=[DataRequired(message='Really need a password, Dude!')])
    submit = SubmitField('Sign Up')

Flask Route

from flask import Flask, render_template, redirect, url_for, flash
app = Flask(__name__)
app.secret_key = 'your_secret_key'  # Required for flashing messages

@app.route('/signup', methods=['GET', 'POST'])
def signup():
    form = SignupForm()
    if form.validate_on_submit():
        # Process the form data (e.g., save to database)
        flash('Signup successful!')
        return redirect(url_for('signup'))
    return render_template('signup.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)

HTML Template (signup.html)

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Signup</title>
</head>
<body>
    <form method="POST" action="{{ url_for('signup') }}" novalidate>
        {{ form.hidden_tag() }}
        <div>
            {{ form.first_name.label }}
            {{ form.first_name }}
            {% if form.first_name.errors %}
                <ul>
                {% for error in form.first_name.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </div>
        <div>
            {{ form.last_name.label }}
            {{ form.last_name }}
            {% if form.last_name.errors %}
                <ul>
                {% for error in form.last_name.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </div>
        <div>
            {{ form.email.label }}
            {{ form.email }}
            {% if form.email.errors %}
                <ul>
                {% for error in form.email.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </div>
        <div>
            {{ form.password.label }}
            {{ form.password }}
            {% if form.password.errors %}
                <ul>
                {% for error in form.password.errors %}
                    <li>{{ error }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </div>
        <div>
            {{ form.submit }}
        </div>
    </form>
</body>
</html>

In this setup:

  • The novalidate attribute is added to the <form> tag to disable the HTML5 validation.
  • Error messages from the Flask-WTF validation are displayed under each field if there are any validation errors.

With this configuration, when the user submits the form, it will be sent to the server, where Flask-WTF will validate the data and return custom error messages if any fields are missing or invalid. These custom error messages will be displayed in the template.