【问题标题】:How to add Bootstrap Validation to WTForms如何将引导验证添加到 WTForms
【发布时间】:2020-04-16 01:17:06
【问题描述】:

我将 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 验证的错误,但我不确定如何将原始表单元素的类更改为 is-invalidis-valid,以及如何为每个错误创建标签。我研究过宏,但它们似乎也无法修改表单元素。

有人能指出正确的方向吗?

【问题讨论】:

    标签: python-3.x flask bootstrap-4 jinja2 wtforms


    【解决方案1】:

    我遇到了同样的问题,我想避免使用任何第三个包(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>
    
    

    诀窍是使用简单的三元表达式结合字符串连接

    【讨论】:

      【解决方案2】:

      @cizario's answer 是一个很好的开始。但是,我为错误找到了更好的实现。使用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)
      

      这将添加无效标记,以便引导程序可以将其标记为无效。在 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>
      

      【讨论】:

        【解决方案3】:

        我最终使用了另一个提供 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>
        

        【讨论】:

          【解决方案4】:

          使用 render_template 渲染模板时,将“is-valid”类传递给您想要的所有元素。用这个

          class = '{{email_valid_class}} all other classes here'
          

          然后在python中return render_template('login.html',email_valid_class='is-valid')

          【讨论】:

          • 我不认为这会按预期添加引导验证。它只为所有字段添加一个is_valid 类。如果您想为所有字段添加is_valid 类,也不需要这样做。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-02-10
          • 1970-01-01
          • 2015-10-24
          • 1970-01-01
          • 2013-11-18
          • 2011-08-27
          • 1970-01-01
          相关资源
          最近更新 更多