flask-wtf EqualTo validator not doing anything

Viewed 317

Im trying to make a registration page and have two password fields: password, and password2.

I have followed the documentation and also tried many different variations from forums and stack overflow questions but none of them seem to work.

Here is my code:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, EmailField
from wtforms.validators import InputRequired, Length, EqualTo

class LoginForm(FlaskForm):
    username = StringField('Username', validators=[InputRequired(), Length(min=4, max=15)])
    password = PasswordField('Password', validators=[InputRequired(), Length(min=8, max=80)])
    remember = BooleanField('Remember Me')

class SignupForm(FlaskForm):
    email = EmailField('Email', validators=[InputRequired(), Length(max=64)])
    username = StringField('Username', validators=[InputRequired(), Length(min=4, max=15)])
    password = PasswordField('Password', validators=[InputRequired(), Length(min=8, max=80)])
    password2  = PasswordField('Confirm Password', validators=[InputRequired(), EqualTo('password', message='Passwords must match')])

and the template:

{% extends 'base.html' %}
{% block content %}

<form class="mx-auto" style="max-width:30rem;" method="POST">
  <h1>{{ title }}</h1>
  <div class="mb-3">
    {{ form.email.label(class_='form-label') }}
    {{ form.email(class_='form-control') }}
  </div>
  <div class="mb-3">
    {{ form.username.label(class_='form-label') }}
    {{ form.username(class_='form-control') }}
  </div>
  <div class="mb-3">
    {{ form.password.label(class_='form-label') }}
    {{ form.password(class_='form-control') }}
  </div>
  <div class="mb-3">
    {{ form.password2.label(class_='form-label') }}
    {{ form.password2(class_='form-control') }}
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

On sumbission, the request gets sent regardless of whether the passwords match or not. Not too sure where I'm going wrong here.

All other validators seem to work as expected

1 Answers

I think the validator just behaves differently to how I expected. I thought that it would flag as a non-matching password when i tried to submit the form, just like it does if the email is anot a valid email address. In reality though it flags the error once the post request is sent to the route. I decided to handle these errors in the route and pass them through to the template like this:

@account.route('/signup', methods=['GET', 'POST'])
def signup():
    form = SignupForm()

    if form.validate_on_submit():
        # username = request.form.get('username')
        # password = request.form.get('password')
        # email = request.form.get('email')

        return 'IT WORKED'
    

    errors = [{'field': key, 'messages': form.errors[key]} for key in form.errors.keys()] if form.errors else []

    return render_template('account/signup.html', title='Signup', 
        form=form, 
        errors=errors
    )

and then in the template:

  <ul>
    {% for field in errors %}
      {% for message in field.messages %}
      <li>{{ message }}</li>
      {% endfor %}
    {% endfor %}
  </ul>

Whether this is best practices I dont know but it works and is relatively clean

Related