在同一个页面模板中分别验证多个 wtf 表单。烧瓶
Validating multiple wtf forms separately, within same page template. Flask
我是使用 Flask 和 wtforms 的初学者。我已经能够使用 Flask-Login 和 wtforms 开发一个基本的登录系统,使用单独的 routes/forms 没有问题。我现在要创建的是一个注册页面,其中包含多个要在同一注册 html 页面中验证的表单。
我的 AccessCodeCheckForm 表单没有得到验证,我找不到问题所在。我已尝试提供尽可能多的代码片段,并注释掉我遇到问题的地方。希望并不过分。如果我的代码中遗漏了什么,请告诉我,您希望我在此处添加,以使其更全面。
感谢您的帮助!
这是我的代码:
models.py
class Users(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
first_nm = db.Column(db.String(64))
last_nm = db.Column(db.String(64))
suffix = db.Column(db.String(4))
profile_img = db.Column(db.String(64), nullable=False, default='default_profile_img.png')
role_id = db.Column(db.Integer, db.ForeignKey('user_roles.role_id'))
grade_id = db.Column(db.Integer, db.ForeignKey('grade_levels.grade_id'))
access_cd = db.Column(db.Integer, db.ForeignKey('access_codes.code_id'))
school_id = db.Column(db.Integer, db.ForeignKey('schools.school_id'))
district_id = db.Column(db.Integer, db.ForeignKey('school_districts.district_id'))
created_dt = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
# add relationship between User table and other tables
users_subjects = db.relationship('Subjects', backref='user', lazy=True)
users_cases = db.relationship('Cases', backref='user', lazy=True)
# initialize method
def __init__(self, email, username, password, role_id, access_cd):
self.email = email
self.username = username
# hash the password passed by the user
self.password_hash = generate_password_hash(password)
self.role_id = role_id
self.access_cd = access_cd
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class AccessCodes(db.Model):
__tablename__ = 'access_codes'
code_id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
access_cd = db.Column(db.String(64), unique=True)
school_id = db.Column(db.Integer, db.ForeignKey('schools.school_id'))
district_id = db.Column(db.Integer, db.ForeignKey('school_districts.district_id'))
created_dtm = db.Column(db.DateTime)
# add relationship between User table and other tables
access_cd = db.relationship('Users', backref='access_cd', lazy=True)
forms.py
class RegistrationForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email("Please provide a valid email address.")])
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired(), EqualTo('pass_confirm', message='Oops!, passwords must match'), Regexp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,32}$', flags=0, message='Password must follow the patterns below')])
pass_confirm = PasswordField('Confirm Password', validators=[DataRequired()])
role_id = HiddenField()
access_cd = HiddenField()
submit = SubmitField('Register!')
def check_email(self,field):
#User.query.filter_by means -- Query user table where email = field variable data
# and grab the first record (first())
if Users.query.filter_by(email = field).first():
return field
def check_username(self, field):
if Users.query.filter_by(username = field).first():
return field
class AccessCodeCheckForm(FlaskForm):
access_cd = StringField('Access Code', validators=[DataRequired()])
submit = SubmitField('Next')
def check_access_code(self, field):
if AccessCodes.query.filter_by(access_cd=field).first():
return field
views.py
# register user
@users.route('/register', methods=['GET','POST'])
def register():
register_form = RegistrationForm()
access_cd_form = AccessCodeCheckForm()
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate_on_submit():
#I am planning to use the check_access_code method here
#but just trying something simple first to check validation success
flash('Get triggered')
elif request.method == 'POST':
if register_form.submit.data and register_form.validate_on_submit():
user = Users(email=register_form.email.data, username=register_form.username.data, password=register_form.password.data,
role_id=register_form.role_id.data, access_cd=register_form.access_cd.data)
flash(f"role id set as {register_form.role_id.data}")
check_email = register_form.check_email(field=register_form.email.data)
check_username = register_form.check_username(field=register_form.username.data)
if check_email is not None:
flash("email already used!")
elif check_username is not None:
flash("username already taken!")
else:
db.session.add(user)
db.session.commit()
# redirect where the class view of the login is at
return redirect(url_for('users.login'))
return render_template('register.html', register_form=register_form, access_cd_form=access_cd_form)
register.html
{% extends "base.html" %}
{% block content %}
<!-- this secion is handled by a javascript function and is working fine-->
<form id="role-selection">
<div class="row align-items-center">
<div class="col">
</div>
<div class="col">
<h1><b>Are you a:</b></h1>
<button onclick="userType(1)">STUDENT</button>
<button onclick="userType(2)">TEACHER</button>
<button onclick="userType(3)">ADMINISTRATOR</button>
</div>
<div class="col">
</div>
</div>
</form>
<!-- this section is the one I am having issues with because it does not gets validated-->
<form method="GET" id="access-code-selection" onsubmit="accessCode()">
{{ access_cd_form.hidden_tag() }} <!-- hidden tag is a CSRF security feature-->
<div class="row align-items-center">
<div class="col">
</div>
<div class="col">
<h1><b>Do you have an existing class, school or District's access code?</b></h1>
{{ access_cd_form.access_cd.label }} {{ access_cd_form.access_cd(class_="form-control") }}
{{ access_cd_form.submit(class_="btn btn-primary") }}
</div>
<div class="col">
</div>
</div>
</form>
<!-- have not even test the submission of this form yet -->
<form method="POST" id="register-container">
{{ register_form.hidden_tag() }} <!-- hidden tag is a CSRF security feature-->
{{ register_form.role_id() }} <!-- hidden tag to specify user role -->
{{ register_form.access_cd() }}
<div class="row align-items-center">
<div class="col">
</div>
<div class="col register-form-column">
<div class="form-group">
{{ register_form.username.label }} {{ register_form.username(class_="form-control") }}
</div>
<div class="form-group">
{{ register_form.email.label }} {{ register_form.email(class_="form-control") }}
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
{% if register_form.email.errors %}
{% for error in register_form.email.errors %}
<p style="color:red;">{{ error }}</p>
{% endfor %}
{% endif %}
<div class="form-group">
{{ register_form.password.label }} {{ register_form.password(class_="form-control", onfocus="showRequirements()") }}
</div>
{% if register_form.password.errors %}
{% for error in register_form.password.errors %}
<p style="color:red;">{{ error }}</p>
{% endfor %}
{% endif %}
<ul id="password-requirements" style="display: none;">
<li>At least one digit [0-9]</li>
<li>At least one lowercase character [a-z]</li>
<li>At least one uppercase character [A-Z]</li>
<li>At least one special character [*.!@#$%^&(){}[]:;<>,.?/~_+-=|\]</li>
<li>At least 8 characters in length, but no more than 32.</li>
</ul>
<div class="form-group">
{{ register_form.pass_confirm.label }} {{ register_form.pass_confirm(class_="form-control") }}
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Agree to term and services</label>
<small class="form-text text-muted">Already have an account? <a href="{{url_for('users.login')}}">Login here!.</a></small>
</div>
{{ register_form.submit(class_="btn btn-primary") }}
</div>
<div class="col">
</div>
</div>
</form>
{% endblock %}
我正在打印出错误并直接在我的 header 上闪烁:
base.html
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible fade show alert-container" role="alert">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
在视图函数中,您以这种方式验证第一个表单:
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate_on_submit():
这里的form.validate_on_submit()
是request.method in ['POST', 'PUT', 'PATCH', 'DELETE'] and form.validate()
的快捷方式。由于您对此表单使用 GET 方法,access_cd_form.validate_on_submit()
将始终 return False,这就是您无法验证表单的原因(请参阅 this answer 中的详细信息)。
我建议将此行更改为:
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate():
顺便说一下,我认为您可以像这样对两种形式使用 POST:
@users.route('/register', methods=['GET','POST'])
def register():
register_form = RegistrationForm()
access_cd_form = AccessCodeCheckForm()
if request.method == 'POST': # use one if statement for request method
if access_cd_form.submit.data and access_cd_form.validate(): # change to validate()
#I am planning to use the check_access_code method here
#but just trying something simple first to check validation success
flash('Get triggered')
if register_form.submit.data and register_form.validate(): # change to validate()
user = Users(email=register_form.email.data, username=register_form.username.data, password=register_form.password.data,
role_id=register_form.role_id.data, access_cd=register_form.access_cd.data)
flash(f"role id set as {register_form.role_id.data}")
check_email = register_form.check_email(field=register_form.email.data)
check_username = register_form.check_username(field=register_form.username.data)
if check_email is not None:
flash("email already used!")
elif check_username is not None:
flash("username already taken!")
else:
db.session.add(user)
db.session.commit()
# redirect where the class view of the login is at
return redirect(url_for('users.login'))
我是使用 Flask 和 wtforms 的初学者。我已经能够使用 Flask-Login 和 wtforms 开发一个基本的登录系统,使用单独的 routes/forms 没有问题。我现在要创建的是一个注册页面,其中包含多个要在同一注册 html 页面中验证的表单。
我的 AccessCodeCheckForm 表单没有得到验证,我找不到问题所在。我已尝试提供尽可能多的代码片段,并注释掉我遇到问题的地方。希望并不过分。如果我的代码中遗漏了什么,请告诉我,您希望我在此处添加,以使其更全面。
感谢您的帮助!
这是我的代码: models.py
class Users(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
first_nm = db.Column(db.String(64))
last_nm = db.Column(db.String(64))
suffix = db.Column(db.String(4))
profile_img = db.Column(db.String(64), nullable=False, default='default_profile_img.png')
role_id = db.Column(db.Integer, db.ForeignKey('user_roles.role_id'))
grade_id = db.Column(db.Integer, db.ForeignKey('grade_levels.grade_id'))
access_cd = db.Column(db.Integer, db.ForeignKey('access_codes.code_id'))
school_id = db.Column(db.Integer, db.ForeignKey('schools.school_id'))
district_id = db.Column(db.Integer, db.ForeignKey('school_districts.district_id'))
created_dt = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
# add relationship between User table and other tables
users_subjects = db.relationship('Subjects', backref='user', lazy=True)
users_cases = db.relationship('Cases', backref='user', lazy=True)
# initialize method
def __init__(self, email, username, password, role_id, access_cd):
self.email = email
self.username = username
# hash the password passed by the user
self.password_hash = generate_password_hash(password)
self.role_id = role_id
self.access_cd = access_cd
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class AccessCodes(db.Model):
__tablename__ = 'access_codes'
code_id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
access_cd = db.Column(db.String(64), unique=True)
school_id = db.Column(db.Integer, db.ForeignKey('schools.school_id'))
district_id = db.Column(db.Integer, db.ForeignKey('school_districts.district_id'))
created_dtm = db.Column(db.DateTime)
# add relationship between User table and other tables
access_cd = db.relationship('Users', backref='access_cd', lazy=True)
forms.py
class RegistrationForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email("Please provide a valid email address.")])
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired(), EqualTo('pass_confirm', message='Oops!, passwords must match'), Regexp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,32}$', flags=0, message='Password must follow the patterns below')])
pass_confirm = PasswordField('Confirm Password', validators=[DataRequired()])
role_id = HiddenField()
access_cd = HiddenField()
submit = SubmitField('Register!')
def check_email(self,field):
#User.query.filter_by means -- Query user table where email = field variable data
# and grab the first record (first())
if Users.query.filter_by(email = field).first():
return field
def check_username(self, field):
if Users.query.filter_by(username = field).first():
return field
class AccessCodeCheckForm(FlaskForm):
access_cd = StringField('Access Code', validators=[DataRequired()])
submit = SubmitField('Next')
def check_access_code(self, field):
if AccessCodes.query.filter_by(access_cd=field).first():
return field
views.py
# register user
@users.route('/register', methods=['GET','POST'])
def register():
register_form = RegistrationForm()
access_cd_form = AccessCodeCheckForm()
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate_on_submit():
#I am planning to use the check_access_code method here
#but just trying something simple first to check validation success
flash('Get triggered')
elif request.method == 'POST':
if register_form.submit.data and register_form.validate_on_submit():
user = Users(email=register_form.email.data, username=register_form.username.data, password=register_form.password.data,
role_id=register_form.role_id.data, access_cd=register_form.access_cd.data)
flash(f"role id set as {register_form.role_id.data}")
check_email = register_form.check_email(field=register_form.email.data)
check_username = register_form.check_username(field=register_form.username.data)
if check_email is not None:
flash("email already used!")
elif check_username is not None:
flash("username already taken!")
else:
db.session.add(user)
db.session.commit()
# redirect where the class view of the login is at
return redirect(url_for('users.login'))
return render_template('register.html', register_form=register_form, access_cd_form=access_cd_form)
register.html
{% extends "base.html" %}
{% block content %}
<!-- this secion is handled by a javascript function and is working fine-->
<form id="role-selection">
<div class="row align-items-center">
<div class="col">
</div>
<div class="col">
<h1><b>Are you a:</b></h1>
<button onclick="userType(1)">STUDENT</button>
<button onclick="userType(2)">TEACHER</button>
<button onclick="userType(3)">ADMINISTRATOR</button>
</div>
<div class="col">
</div>
</div>
</form>
<!-- this section is the one I am having issues with because it does not gets validated-->
<form method="GET" id="access-code-selection" onsubmit="accessCode()">
{{ access_cd_form.hidden_tag() }} <!-- hidden tag is a CSRF security feature-->
<div class="row align-items-center">
<div class="col">
</div>
<div class="col">
<h1><b>Do you have an existing class, school or District's access code?</b></h1>
{{ access_cd_form.access_cd.label }} {{ access_cd_form.access_cd(class_="form-control") }}
{{ access_cd_form.submit(class_="btn btn-primary") }}
</div>
<div class="col">
</div>
</div>
</form>
<!-- have not even test the submission of this form yet -->
<form method="POST" id="register-container">
{{ register_form.hidden_tag() }} <!-- hidden tag is a CSRF security feature-->
{{ register_form.role_id() }} <!-- hidden tag to specify user role -->
{{ register_form.access_cd() }}
<div class="row align-items-center">
<div class="col">
</div>
<div class="col register-form-column">
<div class="form-group">
{{ register_form.username.label }} {{ register_form.username(class_="form-control") }}
</div>
<div class="form-group">
{{ register_form.email.label }} {{ register_form.email(class_="form-control") }}
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
{% if register_form.email.errors %}
{% for error in register_form.email.errors %}
<p style="color:red;">{{ error }}</p>
{% endfor %}
{% endif %}
<div class="form-group">
{{ register_form.password.label }} {{ register_form.password(class_="form-control", onfocus="showRequirements()") }}
</div>
{% if register_form.password.errors %}
{% for error in register_form.password.errors %}
<p style="color:red;">{{ error }}</p>
{% endfor %}
{% endif %}
<ul id="password-requirements" style="display: none;">
<li>At least one digit [0-9]</li>
<li>At least one lowercase character [a-z]</li>
<li>At least one uppercase character [A-Z]</li>
<li>At least one special character [*.!@#$%^&(){}[]:;<>,.?/~_+-=|\]</li>
<li>At least 8 characters in length, but no more than 32.</li>
</ul>
<div class="form-group">
{{ register_form.pass_confirm.label }} {{ register_form.pass_confirm(class_="form-control") }}
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Agree to term and services</label>
<small class="form-text text-muted">Already have an account? <a href="{{url_for('users.login')}}">Login here!.</a></small>
</div>
{{ register_form.submit(class_="btn btn-primary") }}
</div>
<div class="col">
</div>
</div>
</form>
{% endblock %}
我正在打印出错误并直接在我的 header 上闪烁: base.html
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible fade show alert-container" role="alert">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
在视图函数中,您以这种方式验证第一个表单:
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate_on_submit():
这里的form.validate_on_submit()
是request.method in ['POST', 'PUT', 'PATCH', 'DELETE'] and form.validate()
的快捷方式。由于您对此表单使用 GET 方法,access_cd_form.validate_on_submit()
将始终 return False,这就是您无法验证表单的原因(请参阅 this answer 中的详细信息)。
我建议将此行更改为:
if request.method == 'GET':
if access_cd_form.submit.data and access_cd_form.validate():
顺便说一下,我认为您可以像这样对两种形式使用 POST:
@users.route('/register', methods=['GET','POST'])
def register():
register_form = RegistrationForm()
access_cd_form = AccessCodeCheckForm()
if request.method == 'POST': # use one if statement for request method
if access_cd_form.submit.data and access_cd_form.validate(): # change to validate()
#I am planning to use the check_access_code method here
#but just trying something simple first to check validation success
flash('Get triggered')
if register_form.submit.data and register_form.validate(): # change to validate()
user = Users(email=register_form.email.data, username=register_form.username.data, password=register_form.password.data,
role_id=register_form.role_id.data, access_cd=register_form.access_cd.data)
flash(f"role id set as {register_form.role_id.data}")
check_email = register_form.check_email(field=register_form.email.data)
check_username = register_form.check_username(field=register_form.username.data)
if check_email is not None:
flash("email already used!")
elif check_username is not None:
flash("username already taken!")
else:
db.session.add(user)
db.session.commit()
# redirect where the class view of the login is at
return redirect(url_for('users.login'))