Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialBenjamin Stanger
Python Web Development Techdegree Student 7,974 PointsHelp with Validators?
Hey there,
I am working on following along with the videos on my own machine. So far everything has been going well. However, when creating the forms, and trying to ensure validation I encounter a problem. I only seem to get a generic "please fill out this field" pop-up dialogue when I hit submit with all my fields empty - none of my validators seem to be applied to any of the fields in my form. At the very least the messages in those validators aren't showing up. I'm wondering if anyone has an insight into this? any help would be greatly appreciated!
--app.py--
import requests
import datetime
from peewee import *
from flask import (Flask, g, render_template, flash, redirect, url_for)
from flask_login import UserMixin, LoginManager
from flask_bcrypt import generate_password_hash, check_password_hash
# imports from the rest of app
import models
import forms
# globla variables that are important for web
DEBUG =True
PORT = 8000
HOST = '0.0.0.0'
# initiate app, add secret key
app = Flask(__name__)
app.secret_key = 'a;sirh.cp34jrgnloijfdishdjs;fgkasfjlsdifs'
# setup LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
@login_manager.user_loader
def load_user(user_id):
try:
return models.User.get(models.User.id == user_id)
except models.DoesNotExist:
return None
# opens link to db before request is made
@app.before_request
def before_request():
"""Connect to the database before each request"""
g.db = models.DATABASE
g.db.connect()
# closes link to db after response is received
@app.after_request
def after_request(response):
"""Close the database connection after each request"""
g.db.close()
return response
# route to form for registering as a new user
@app.route('/register',methods=['GET', 'POST'])
def register():
form = forms.RegisterForm()
if form.validate_on_submit():
flash("yay, you registered", "success")
models.User.create_user(
username=form.username.data,
email=form.email.data,
password = form.password.data
)
return redirect(url_for('index'))
return render_template('register.html', form = form)
@app.route('/')
def index():
return 'Hey'
# runs the actual app
if __name__ == '__main__':
models.initialize()
try:
models.User.create_user(
username = 'User Test',
email = 'usertest@example.com',
password = 'p4ssw0rd',
admin = True)
except ValueError:
pass
app.run(debug = DEBUG, host = HOST, port = PORT)
--forms.py--
from flask_wtf import FlaskForm
from peewee import *
from wtforms import StringField, PasswordField
from wtforms.validators import (DataRequired, Regexp, ValidationError, Email,
Length, EqualTo, InputRequired)
from models import User
def name_exists(form, field):
if User.select().where(User.username == field.data).exists():
raise ValidationError('User with that name already exists')
def email_exists(form, field):
if User.select().where(User.email == field.data).exists():
raise ValidationError('User with that email already exists')
class RegisterForm(FlaskForm):
username = StringField(
'Username',
validators=[
InputRequired(message='askdjfakds'),
Regexp(
r'^[a-zA-z0-9_]+$', message=("Username should be one word, "
" letters, numbers and underscores only")
),
name_exists
])
email = StringField(
'Email',
validators=[
InputRequired(),
Email(),
email_exists
])
password = PasswordField(
'Password',
validators=[
InputRequired(),
Length(min=7),
EqualTo('password2', message='Passwords must match')
])
password2 = PasswordField(
'Confirm Password',
validators =[InputRequired()])
--register.html--
{% from 'macros.html' import render_field %}
<form method='POST' action='' class='form'>
{{ form.hidden_tag() }}
{% for field in form %}
{{ render_field(field) }}
{% endfor %}
<button type='submit' id='submit'>Register</button>
</form>
--macros.html--
{% macro render_field(field) %}
<div class = 'field'>
{% if field.errors %}
{% for error in field.errors %}
<div class='notification error'>{{ error }}</div>
{% endfor %}
{% endif %}
{{ field(placeholder=field.label.text) }}
</div>
{% endmacro %}
Chris Howell
Python Web Development Techdegree Graduate 49,702 PointsChanged Post
- Added language specific syntax highlighting.
- Removed personal details from your Dunder Main (name, email, password).
Hey Benjamin Stanger, was skimming over your post. Just giving you a heads up that I modified your post. This Community Forum is public and searchable by the entire internet. I wanted to protect what potentially looked like actual personal details. My main concern was the email and password you had provided. :)
1 Answer
Chris Howell
Python Web Development Techdegree Graduate 49,702 PointsHey Benjamin Stanger
So this generic "Please fill out this field" pop-up that you are getting potentially sounds like its coming from the rendered HTML Form. This is actually one or more of your form validators causing this. But these specific validators not only apply their behavior to the backend processing of the form, but they also are applied inside the actual HTML of the page. This is to help prevent accidental/invalid form submissions from even having to be sent as a POST request as they are handled on the client side.
It basically is adding into the <input>
element the required
property so the form itself can stop a form submission. The user could still force this submission if they had a little know-how. In that case, they would then be invalidated by the back-end logic.
So the code in your form applying these front-end rendered form properties are these:
class RegisterForm(FlaskForm):
username = StringField(
'Username',
validators=[
InputRequired(message='askdjfakds'),
# ^ The line above makes this field REQUIRE input
# from the front end rendering of the form,
# and when processed on submit.
Regexp(
r'^[a-zA-z0-9_]+$', message=("Username should be one word, "
" letters, numbers and underscores only")
),
name_exists
])
email = StringField(
'Email',
validators=[
InputRequired(),
# ^ The line above makes this field REQUIRE input
# from the front end rendering of the form,
# and when processed on submit.
Email(),
email_exists
])
password = PasswordField(
'Password',
validators=[
InputRequired(),
# ^ The line above makes this field REQUIRE input
# from the front end rendering of the form,
# and when processed on submit.
Length(min=7),
EqualTo('password2', message='Passwords must match')
])
password2 = PasswordField(
'Confirm Password',
validators =[InputRequired()])
Try tweaking those validators I marked, like removal all of them and try to submit the form. See if it starts to become clear what is happening. You can also load the form page and check the <input>
fields of the form and look for the required
attribute.
Gene Higgins
16,582 PointsI'm not sure how this answer addresses the question: why aren't my notification error divs (showing the form validation error text) showing up. I feel like Chris Howell is answering the question: how do validation messages work?
Is the code in this course still valid? This place feels like a ghost town.
Benjamin Stanger
Python Web Development Techdegree Student 7,974 PointsBenjamin Stanger
Python Web Development Techdegree Student 7,974 PointsI read somewhere that it's possible the page/form is being updated after a failed submit, and therefor not showing the validation error messages. However, I looked over the videos and a few other questions that have been posed, and my code seems to follow everyone else's pretty closely! I've also checked over the wtforms docs a decent amount and cannot see any problem there. My guess it has something to do with the way I am loading the form, but I am really not sure. Again, any help is really appreciated! =]