0

I would like a little bit of help into understanding how the validation function in this case. I have the following code: 1. forms.py - here I define my form

    from flask_wtf import FlaskForm
    from wtforms import StringField, PasswordField, SubmitField, BooleanField
    import email_validator
    from wtforms.validators import DataRequired, Length, Email, EqualTo


    class RegistrationForm(FlaskForm):
        username = StringField('Username',
                               validators=[DataRequired(),
                                           Length(min=2, max=20)])

        email = StringField('Email',
                            validators=[DataRequired(), Email()])

        password = PasswordField('Password',
                                 validators=[DataRequired()])

        confirm_password = PasswordField('Confirm Password',
                                         validators=[DataRequired(),
                                                     EqualTo('password')])

        submit = SubmitField('Sign Up')
  1. app.py - the main app
    from flask import Flask, render_template, url_for, flash, redirect
    from forms import RegistrationForm, LoginForm

    app = Flask(__name__)

    app.config['SECRET_KEY'] = 'giberish'


    @app.route("/")
    @app.route("/home")
    def home():
        return render_template("home.html", title="Home", posts=posts)


    @app.route('/register', methods=['GET', 'POST'])
    def register():
        form = RegistrationForm()
        if form.validate_on_submit():
            flash(f'Account created for {form.username.data}!', 'success')
            return redirect(url_for('home'))
        return render_template('register.html', title='register', form=form)


    if __name__ == '__main__':
        app.run(debug=True)
  1. register.html - the template
{% 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>
  </div>
  <div class="border-top pt-3">
    <small class="text-muted">
      Already Have An Account? <a href="{{url_for('login')}}" class="ml-2">Sign In</a>.
    </small>
  </div>
  {% if form.errors %}
      {{ form.errors }}
  {% endif %}
{% endblock content %}

As some could see this is from the videos of Corey Schafer and the code functions, but not exactly as expected at least in the case when I submit an empty form.

In the video from Corey when he submits an empty form than the form.field.errors gets populated and the errors are displayed below each field.

In my case I only get the fields with a red outline and a pop up with please fill in this field. I would like to know if either I am doing something wrong or this is eventually a new behavior in form validation.

I spend several hours trying to understand and I have not managed. In the case when I fill in one character than the form.field.errors gets populated and the error messages are displayed. My bed is on the fact that the DataRequired() validator is somehow short-circuiting the validation, but I am not 100% sure as I am a beginner in this.

I would appreciate also eventually a way of approaching this type of errors and where to look for such small details (into documentation or (my) code).

Thanks!

2 Answers 2

2

Thanks to Akib Rhast I have found the answer: it is in the change log for wtforms 2.2 and has something to do with this pull request:

Widgets render the required attribute when using a validator that provides the 'required' flag, such as DataRequired. #361

Using the wtforms 2.1 I can confirm that the behavior is as per Corey's video on youtube and the error messages are displayed below the form field upon empty submit.

From version 2.2 onward the verification is done before post in case of empty submits.

The take away from here: read the docs boys and girls. Thanks once again Akib Rhast!!!

Sign up to request clarification or add additional context in comments.

Comments

1

I believe the reason for the above mentioned behaviour is due to this line from the docs :

class wtforms.validators.DataRequired(message=None) source

If the data is empty, also removes prior errors (such as processing errors) from the field.

So, to achieve what you want replace replace these :

username = StringField('Username', validators=[DataRequired(),Length(min=2, max=20)])

with these :

username = StringField('Username', validators=[InputRequired(),Length(min=2, max=20)])

Because according to the above linked documentation page:

Unless a very specific reason exists, we recommend using the InputRequired instead.

Let me know if that answers your question and resolves your issue :D

1 Comment

not exactly... looking in the description of InputRequired I have found the following: "Note there is a distinction between this and DataRequired in that InputRequired looks that form-input data was provided, and DataRequired looks at the post-coercion data."... so in my case it seems that DataRequired validator is behaving as InputRequired as its looking at the data pre-coercion...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.