I have used the built-in validators, but none of them is printing a message on the page. Also, I want to create a custom validator to check duplicate username. I have written the function, as I am a beginner, I don't know how to use it. Pls resolve the problem.
from flask import Flask, app, render_template, request, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from wtforms.validators import InputRequired, EqualTo, ValidationError
app = Flask(__name__)
app.config['SECRET_KEY'] = "PQrs12t46uvvrty567"
class MyForm(FlaskForm):
username = StringField('Username', validators=[InputRequired(message="This field is required.")])
password=PasswordField('Password', validators=[InputRequired(message=("enter the password"))])
confirm_password=PasswordField('Confirm Password', validators=[EqualTo('password')])
submit = SubmitField('Register')
def isDuplicate():
appdatabase={"Alis":"Smith","Mike":"Brown","Paul":"Miller"}
form = MyForm()
for user in appdatabase:
if form.username == appdatabase[user]:
raise ValidationError("Username already exists! Please choose another one.")
@app.route('/')
def base():
form = MyForm()
return render_template('customvalidator.html', form = form)
@app.route('/submitform', methods=["GET","POST"])
def submitform():
form = MyForm()
if form.validate_on_submit():
return 'Form accepted successfully.'
else:
return 'Incorrect form data'
if __name__=="__main__":
app.run(debug=True)
HTML file
<!DOCTYPE html>
<html>
<head><title>My website</title></head>
<body>
<h1>Registration form</h1>
<form action="{{ url_for('submitform') }}" method="post">
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username }}
<ul>
{% for error in form.username.errors %}
<li style="color: red;">{{ error }} </li>
{% endfor %}
</ul>
<br>
{{ form.password.label }}
{{ form.password }} <br><br>
{{ form.confirm_password.label }}
{{ form.confirm_password }} <br><br>
{{ form.submit}}
</form>
</body>
</html>
CodePudding user response:
Try changing the isDuplicate
function to this:
def isDuplicate(form, field):
appdatabase={"Alis":"Smith","Mike":"Brown","Paul":"Miller"}
form = MyForm()
for user in appdatabase:
if form.username.data == appdatabase[user]:
raise ValidationError("Username already exists! Please choose another one.")
Notice the added form and field parameters to the function to allow its use as a custom validator. form.username
was also changed to form.username.data
to access the data of the username field. (This whole function will need to be defined before the form.)
You will then need to add this custom validator to your list of validators for the username field in your form like so:
username = StringField('Username', validators=[InputRequired(message="This field is required."),isDuplicate])
With these changes, the custom validation should work, but we still haven't solved the issue of the custom error messages. To do this, add a novalidate
attribute to your HTML form tag. Adding this will disable the default validation on forms and allow you to display custom messages.
With that in place, I believe the messages still won't work because of how you are handling the form submission. When the form does not validate, you will want to display the same form template instead of showing them whether it submitted or not.
My personal opinion is that merging your two form routes will be the simplest option. Have a route define the form, check for when it gets validated or not, and then render the form template. This will enable you to keep everything together and not render a different template when you only want to display the same template with a few added error messages.
Credits:
- Custom validators (check the last point)
- SO question on displaying validation messages
- -which led me to this one on actually how to disable the default messages.