3

我想创建一个带有 WTForms 的表单,其中字段是具有特殊(自定义)验证的 SelectField,(例如)如果当前值无效(即它不是已定义选项的实例),则检查其他内容。

我在文档中读到正确的方法是覆盖功能pre_validatepost_validate根据需要。

所以我的方法如下:

1 - 我创建了一个名为 MySelectForm 的新字段:

class MySelectField(SelectField):
    def post_validate(self, form, validation_stopped):
        """overrides post validation"""
        #Here is my custom validation

2- 我使用此字段而不是表单中的原始字段

我无法理解的是:如果,就像我在文档中读到的那样,post_validate输入“字段所属的表单”,我如何访问作为实例的字段的当前值MySelectField

换句话说,有人可以举例说明如何覆盖pre_validateorpost_validate吗?

4

2 回答 2

0

您正在传递self给该方法,因此您的字段对象可用。它继承自 WTForms 的Field类,因此您应该可以 使用它field.data。这包含“调用任一过程方法的结果(清理)值”。

于 2013-08-07T21:34:26.340 回答
0

以下是部分源代码

# wtforms.fields.core.py  |  version: Flask-WTF 0.14.3

class Field(object):
    errors = tuple()
    ...

    def validate(self, form, extra_validators=tuple()):
        self.errors = list(self.process_errors)
        stop_validation = False

        self.check_validators(extra_validators)

        try:
            self.pre_validate(form)   # <---------- focus here
        except StopValidation as e:
            if e.args and e.args[0]:
                self.errors.append(e.args[0])
            stop_validation = True
        except ValueError as e:
            self.errors.append(e.args[0])

        # Run validators
        if not stop_validation:
            chain = itertools.chain(self.validators, extra_validators)
            stop_validation = self._run_validation_chain(form, chain)  # <-- It will run ``InputRequired, YourValidators1, YourValidators2, validate_username``  (see the example code)

        # Call post_validate
        try:
            self.post_validate(form, stop_validation)  # <---------- focus here
        except ValueError as e:
            self.errors.append(e.args[0])

        return len(self.errors) == 0

我给你举个例子post_validatepre_validate非常相似,我相信你可以自己做)

from flask_wtf import FlaskForm, Form
from wtforms import StringField, ValidationError, StopValidation
from wtforms.validators import InputRequired
from typing import List


class StateStringField(StringField):
    ok_msg_list: List = None  # Because class ``wtforms.fields.core.Field`` are not existed any attributes I like, so I create one.

    def post_validate(self, form: Form, stop_validation: bool):
        if self.ok_msg_list is None:
            self.ok_msg_list = []
        if stop_validation:
            return
        if not 'errors':  # assume no errors...
            raise ValueError('...')
        else:
            self.ok_msg_list.append('OK')


class UserForm(FlaskForm):
    username = StateStringField('User',
                                validators=[InputRequired(),
                                            # YourValidators2, YourValidators3
                                            ])

    def validate_username(self, field: StringField):
        if len(field.data) > 50:
            raise StopValidation('Name must be less than 50 characters')
<!-- templates/auth/register.html-->
<form method="post">   
    {{ form.hidden_tag() }}
    <p>{{ form.username.label }} {{ form.username()|safe }}
      {% if form.username.errors %}
        {% for error in form.username.errors %}
          <p style="color:red;">{{ error }}<p>
        {% endfor %}
      {% endif %}

      {% if form.username['ok_msg_list'] %}  <!-- similar as python: if hasattr('ok_msg_list') -->
        {% for ok_msg in form.username.ok_msg_list %}
          <span style="color:blue;">{{ ok_msg|safe }}</span>
        {% endfor %}
      {% endif %}
    </p>
</form>

概括

您可以在执行完所有post_validate验证后想要执行另一次验证时使用。(个人认为与.post_validatefinally

在我的示例中,当用户验证所有验证都正确时,旁边会出现一条 OK 消息。

在此处输入图像描述

于 2020-11-12T08:23:19.983 回答