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:
- Disable the HTML5 validation in your Flask-WTF form by adding the
novalidate
attribute to the form. - 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.