如何向 WTForms 添加 Bootstrap 验证
How to add Bootstrap Validation to WTForms
我正在将 WTForms 与 Flask 结合使用,我想在我的表单中集成 Bootstrap Form Validation 错误。我有一个基本的登录表单设置,如下所示:
class LoginForm(FlaskForm):
"""Login form."""
email = EmailField(
"Email Address", validators=[DataRequired(), Email(), Length(min=6, max=40)]
)
password = PasswordField(
"Password", validators=[DataRequired()]
)
def __init__(self, *args, **kwargs):
"""Create instance."""
super(LoginForm, self).__init__(*args, **kwargs)
self.user = None
def validate(self):
"""Validate the form."""
initial_validation = super(LoginForm, self).validate()
if not initial_validation:
return False
self.user = User.query.filter_by(email=self.email.data).first()
if not self.user:
self.email.errors.append("Unknown email address!")
return False
if not self.user.check_password(self.password.data):
self.password.errors.append("Invalid password!")
return False
if not self.user.verified:
self.email.errors.append("Please verify your email address!")
return False
return True
我的 login.html 模板设置如下:
<form method="POST" action="{{ url_for('public.login') }}" role="form">
{{ form.csrf_token }}
<div class="form-group">
{{ form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
{{ form.email(placeholder="name@example.com", class_="form-control") }}
</div>
</div>
<div class="form-group mb-4">
<div class="d-flex align-items-center justify-content-between">
<div>
{{ form.password.label(class_="form-control-label") }}
</div>
<div class="mb-2">
<a href="{{ url_for('public.recover') }}" class="small text-muted text-underline--dashed border-primary">Lost password?</a>
</div>
</div>
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
{{ form.password(placeholder="Password", class_="form-control") }}
<div class="input-group-append" onclick="togglePassword()">
<span class="input-group-text">
<i class="fas fa-eye"></i>
</span>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-auto mt-1 mb-2" align="center">
<button type="submit" class="btn btn-sm btn-primary btn-icon rounded-pill">
<span class="btn-inner--text">Sign in</span>
<span class="btn-inner--icon"><i class="fas fa-long-arrow-alt-right"></i></span>
</button>
</div>
<div class="col-md-auto text-center mt-2">
<p class="text-secondary-dark">or</p>
</div>
<div class="col-md-auto" align="center">
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-google"></i>
</span>
</button>
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-linkedin"></i>
</span>
</button>
</div>
</div>
</form>
我想显示我使用 WTForms 验证的错误,但我不确定如何将原始表单元素的 class 更改为 is-invalid
或 is-valid
,以及如何为每个错误创建标签。我研究过宏,但它们似乎也无法修改表单元素。
有人能给我指出正确的方向吗?
使用 render_template 呈现模板时,将 'is-valid' class 传递给所有您想要的元素。使用这个
class = '{{email_valid_class}} all other classes here'
然后在pythonreturn render_template('login.html',email_valid_class='is-valid')
我遇到了同样的问题,我想避免使用任何第三个包 (flask-bootstrap),我想出了这个简单的解决方案:
<div class="form-group">
{{ form.email.label }} <span class="text-danger">*</span>
{# her #}
{{ form.email(class="form-control" + (" is-invalid" if form.email.errors else "") + " rounded-0 shadow-none", **{"placeholder": "Your Email", "aria-describedby": "emailHelp", "autocomplete": "off"}) }}
<small id="emailHelp" class="form-text text-muted">We'll never share your data with anyone else.</small>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
诀窍是使用简单的三元表达式结合字符串连接。
is a great start. However, I found a better implementation for the errors. Using WTForm's Custom Widgets,您将获得以下小部件:
from wtforms.widgets import PasswordInput, CheckboxInput, TextInput
from wtforms.widgets.html5 import EmailInput
class BootstrapVerifyEmail(EmailInput):
"""Bootstrap Validator for email"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyEmail, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyEmail, self).__call__(field, **kwargs)
class BootstrapVerifyPassword(PasswordInput):
"""Bootstrap Validator for password"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyPassword, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyPassword, self).__call__(field, **kwargs)
class BootstrapVerifyBoolean(CheckboxInput):
"""Bootstrap Validator for boolean"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyBoolean, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyBoolean, self).__call__(field, **kwargs)
class BootstrapVerifyText(TextInput):
"""Bootstrap Validator for text"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyText, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyText, self).__call__(field, **kwargs)
这将添加无效标签,以便 bootstrap 可以将其标记为无效。在 HTML 中,执行类似这样的操作以添加错误消息:
{{ login_user_form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text" id="user"><i class="fas fa-user"></i></span>
</div>
{{ login_user_form.email(placeholder="name@example.com", class_="form-control", **{"aria-describedby": "inputGroupPrepend3", "required": ""}) }}
{% for error in login_user_form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</div>
我最终使用了提供 Bootstrap 小部件的不同库:
https://github.com/agdsn/wtforms-widgets
用法变得非常简单非常快:
from wtforms import validators
from wtforms.validators import Email
from wtforms_widgets.base_form import BaseForm
from wtforms_widgets.fields.core import StringField, PasswordField
class RegisterForm(BaseForm):
email = StringField('Email Address', [Email(), validators.DataRequired(message='Forgot your email address?')])
password = PasswordField('Password', [validators.DataRequired(message='Must provide a password. ;-)')])
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field(render_mode='horizontal', autocomplete='off') }}
{% endfor %}
<input type="submit" value="submit">
</form>
但这不包括验证。
为了添加验证,我把它放在 Jinja 中:
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field() }}
{% for error in field.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endfor %}
<input type="submit" value="submit">
</form>
对于闪现消息,我在我的基地 layout.html
中使用了这个,我 extend
无处不在:
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{% if category == 'message' %}
<div class="alert alert-warning" role="alert">
{% else %}
<div class="alert alert-{{ category }}" role="alert">
{% endif %}
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
我正在将 WTForms 与 Flask 结合使用,我想在我的表单中集成 Bootstrap Form Validation 错误。我有一个基本的登录表单设置,如下所示:
class LoginForm(FlaskForm):
"""Login form."""
email = EmailField(
"Email Address", validators=[DataRequired(), Email(), Length(min=6, max=40)]
)
password = PasswordField(
"Password", validators=[DataRequired()]
)
def __init__(self, *args, **kwargs):
"""Create instance."""
super(LoginForm, self).__init__(*args, **kwargs)
self.user = None
def validate(self):
"""Validate the form."""
initial_validation = super(LoginForm, self).validate()
if not initial_validation:
return False
self.user = User.query.filter_by(email=self.email.data).first()
if not self.user:
self.email.errors.append("Unknown email address!")
return False
if not self.user.check_password(self.password.data):
self.password.errors.append("Invalid password!")
return False
if not self.user.verified:
self.email.errors.append("Please verify your email address!")
return False
return True
我的 login.html 模板设置如下:
<form method="POST" action="{{ url_for('public.login') }}" role="form">
{{ form.csrf_token }}
<div class="form-group">
{{ form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
{{ form.email(placeholder="name@example.com", class_="form-control") }}
</div>
</div>
<div class="form-group mb-4">
<div class="d-flex align-items-center justify-content-between">
<div>
{{ form.password.label(class_="form-control-label") }}
</div>
<div class="mb-2">
<a href="{{ url_for('public.recover') }}" class="small text-muted text-underline--dashed border-primary">Lost password?</a>
</div>
</div>
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
{{ form.password(placeholder="Password", class_="form-control") }}
<div class="input-group-append" onclick="togglePassword()">
<span class="input-group-text">
<i class="fas fa-eye"></i>
</span>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-auto mt-1 mb-2" align="center">
<button type="submit" class="btn btn-sm btn-primary btn-icon rounded-pill">
<span class="btn-inner--text">Sign in</span>
<span class="btn-inner--icon"><i class="fas fa-long-arrow-alt-right"></i></span>
</button>
</div>
<div class="col-md-auto text-center mt-2">
<p class="text-secondary-dark">or</p>
</div>
<div class="col-md-auto" align="center">
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-google"></i>
</span>
</button>
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-linkedin"></i>
</span>
</button>
</div>
</div>
</form>
我想显示我使用 WTForms 验证的错误,但我不确定如何将原始表单元素的 class 更改为 is-invalid
或 is-valid
,以及如何为每个错误创建标签。我研究过宏,但它们似乎也无法修改表单元素。
有人能给我指出正确的方向吗?
使用 render_template 呈现模板时,将 'is-valid' class 传递给所有您想要的元素。使用这个
class = '{{email_valid_class}} all other classes here'
然后在pythonreturn render_template('login.html',email_valid_class='is-valid')
我遇到了同样的问题,我想避免使用任何第三个包 (flask-bootstrap),我想出了这个简单的解决方案:
<div class="form-group">
{{ form.email.label }} <span class="text-danger">*</span>
{# her #}
{{ form.email(class="form-control" + (" is-invalid" if form.email.errors else "") + " rounded-0 shadow-none", **{"placeholder": "Your Email", "aria-describedby": "emailHelp", "autocomplete": "off"}) }}
<small id="emailHelp" class="form-text text-muted">We'll never share your data with anyone else.</small>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
诀窍是使用简单的三元表达式结合字符串连接。
from wtforms.widgets import PasswordInput, CheckboxInput, TextInput
from wtforms.widgets.html5 import EmailInput
class BootstrapVerifyEmail(EmailInput):
"""Bootstrap Validator for email"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyEmail, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyEmail, self).__call__(field, **kwargs)
class BootstrapVerifyPassword(PasswordInput):
"""Bootstrap Validator for password"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyPassword, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyPassword, self).__call__(field, **kwargs)
class BootstrapVerifyBoolean(CheckboxInput):
"""Bootstrap Validator for boolean"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyBoolean, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyBoolean, self).__call__(field, **kwargs)
class BootstrapVerifyText(TextInput):
"""Bootstrap Validator for text"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyText, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyText, self).__call__(field, **kwargs)
这将添加无效标签,以便 bootstrap 可以将其标记为无效。在 HTML 中,执行类似这样的操作以添加错误消息:
{{ login_user_form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text" id="user"><i class="fas fa-user"></i></span>
</div>
{{ login_user_form.email(placeholder="name@example.com", class_="form-control", **{"aria-describedby": "inputGroupPrepend3", "required": ""}) }}
{% for error in login_user_form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</div>
我最终使用了提供 Bootstrap 小部件的不同库:
https://github.com/agdsn/wtforms-widgets
用法变得非常简单非常快:
from wtforms import validators
from wtforms.validators import Email
from wtforms_widgets.base_form import BaseForm
from wtforms_widgets.fields.core import StringField, PasswordField
class RegisterForm(BaseForm):
email = StringField('Email Address', [Email(), validators.DataRequired(message='Forgot your email address?')])
password = PasswordField('Password', [validators.DataRequired(message='Must provide a password. ;-)')])
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field(render_mode='horizontal', autocomplete='off') }}
{% endfor %}
<input type="submit" value="submit">
</form>
但这不包括验证。
为了添加验证,我把它放在 Jinja 中:
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field() }}
{% for error in field.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endfor %}
<input type="submit" value="submit">
</form>
对于闪现消息,我在我的基地 layout.html
中使用了这个,我 extend
无处不在:
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{% if category == 'message' %}
<div class="alert alert-warning" role="alert">
{% else %}
<div class="alert alert-{{ category }}" role="alert">
{% endif %}
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>