简体   繁体   中英

Flask WTForms custom validators not working

So I'm trying to implement custom validators in my Flask App, and I'm running into a problem. The custom validator I wrote for RegisterForm, UniqueRequired() seems to be working, but my validators for LoginForm don't even seem to be being called at all, with the print statement in ValidUsername() not printing. I've already tried putting the validators in the same file, importing them in the different statements, and changing the order of the validators, but nothing works.

Here is my forms.py file:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo
from validators import UniqueRequired, VaildUsername, ValidPassword

class LoginForm(FlaskForm):
    username = StringField("Username:", validators=[DataRequired(), VaildUsername], id="username")
    password = PasswordField("Password:", validators=[DataRequired(), ValidPassword], id="password")

class RegisterForm(FlaskForm):
    username = StringField("Username:", validators=[DataRequired(), UniqueRequired, Length(min=5, max=25)], id="username")
    password = PasswordField("Password:", validators=[DataRequired(), Length(min=8)], id="password")
    confirmpassword = PasswordField("Confirm Password:", validators=[DataRequired(), EqualTo('password', message="Passwords don't match")], id="conpassword")

My validators.py file:

def UniqueRequired(form, field):
    otheruser = User.query.filter_by(username=field.data).first()
    if otheruser:
        raise ValidationError("Username Taken")

def VaildUsername(form, field):
    user = User.query.filter_by(username=field.data).first()
    print(user)
    if not user:
        raise ValidationError("Invalid Username")

def ValidPassword(form, field):
    user = User.query.filter_by(username=form.username.data).first()
    if not check_password_hash(user.password, field.data):
        raise ValidationError("Incorrect Password")

and my /login and /register routes:

@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit:
        print("Form Valid")
    return render_template("login.html", form=form)

@app.route("/register", methods=["GET", "POST"])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        print("Form Valid")
    return render_template("register.html", form=form)

I can think of 2 possible solutions
First : I think there should be set of Parenthesis after your custom validators in validators list.

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo
from validators import UniqueRequired, VaildUsername, ValidPassword

class LoginForm(FlaskForm):
    username = StringField("Username:", validators=[DataRequired(), VaildUsername()], id="username")
    password = PasswordField("Password:", validators=[DataRequired(), ValidPassword()], id="password")

class RegisterForm(FlaskForm):
    username = StringField("Username:", validators=[DataRequired(), UniqueRequired(), Length(min=5, max=25)], id="username")
    password = PasswordField("Password:", validators=[DataRequired(), Length(min=8)], id="password")
    confirmpassword = PasswordField("Confirm Password:", validators=[DataRequired(), EqualTo('password', message="Passwords don't match")], id="conpassword")

Second : You can create a separate method for each class members in the Form Class.
They will automatically be called when validate_on_submit is called.
You can do this

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo

class LoginForm(FlaskForm):
    username = StringField("Username:", validators=[DataRequired()], id="username")
    password = PasswordField("Password:", validators=[DataRequired(), ValidPassword], id="password")
 # validate_<fieldname>  method will automatically validate
    def validate_username(self,field):
    user = User.query.filter_by(username=field.data).first()
    # print(user)
    if not user:
        raise ValidationError("Invalid Username")

    class RegisterForm(FlaskForm):
        username = StringField("Username:", validators=[DataRequired(), UniqueRequired, Length(min=5, max=25)], id="username")
        password = PasswordField("Password:", validators=[DataRequired(), Length(min=8)], id="password")
        confirmpassword = PasswordField("Confirm Password:", validators=[DataRequired(), EqualTo('password', message="Passwords don't match")], id="conpassword")

I have given example of only username field in LoginForm as you can see, you can do similarly for other fields also.

Alright, I've been poking around and I found the problem. In my /login route, I used form.validate_on_submit, but I didn't put any parentheses. The corrected code looks like this:

@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        print("Form Valid")
    return render_template("login.html", form=form)

@app.route("/register", methods=["GET", "POST"])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        print("Form Valid")
    return render_template("register.html", form=form)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM