wtforms.BooleanField的DataRequired验证器失效

5 投票
1 回答
2832 浏览
提问于 2025-04-18 06:40

我正在使用WTForms(配合Flask、flask-wtf和sqlalchemy)来验证REST API接收到的JSON数据。我知道WTForms主要是为了处理HTML表单的渲染和验证,但我选择它是因为它可以根据我的sqlalchemy模型自动生成表单(多亏了wtforms.ext.sqlalchemy)。

不过,我遇到了一个问题。我的一个模型包含一个布尔类型的字段,这在WTForms中对应的是wtforms.BooleanField,并且使用了DataRequired验证器。问题是,即使我传入了正确的数据,验证仍然失败,并显示“这个字段是必填的”错误信息。我的表单如下:

class MyForm(Form):
    name = TextField('name', validators=[DataRequired()])
    disabled = BooleanField('disabled', validators=[DataRequired()])

接收到的JSON数据是这样的:

'{"name": "John", "disabled": "false"}'

我期望的结果是:

  1. {"disabled": "false"} -> 验证成功,转换后的Python数据是:{'disabled': False}
  2. {"disabled": "true"} -> 验证成功,转换后的Python数据是:{'disabled': True}
  3. {"disabled": ""} 或者 '{"disabled": "foo"}' -> 验证失败

目前在第一种情况下,验证失败,返回的结果是{'disabled': [u'This field is required.']}

我知道在文档中有提到,DataRequired验证器“需要转换后的数据,而不是输入的数据”,但是1)这个表单是由wtforms.ext.sqlalchemy自动生成的,2)如果我使用InputRequired验证器,它应该如何工作?是先检查(通过form.validate())是否有某些数据存在,然后再检查这些数据是否是“真”或“假”?

总结一下,我的问题是:

  1. 验证wtforms.BooleanField的正确方法是什么?
  2. 有没有其他框架可以根据给定的sqlalchemy模型来验证接收到的JSON数据?

谢谢。

1 个回答

0

有很多方法可以解决这个问题。你可以自己写一个转换器,利用单选框来选择真或假;也可以使用数据过滤器;还可以设置一个默认值。不过,我觉得你想要的效果可以通过下面这个方法实现:

MyForm = model_form(MyModel, db_session=db, field_args = {
    'disabled' : {
        'false_values': ['false'],
        'validators' : [InputRequired()] }
})

补充:如果你想要一个更严格的处理方式,可以这样做:

class BooleanRequired(object):
    field_flags = ('required', )

    def __init__(self, message=None):
        self.message = message

    def __call__(self, form, field):
        if field.data is None:
            if self.message is None:
                message = field.gettext('This field is required.')
            else:
                message = self.message

            field.errors[:] = []
            raise StopValidation(message)


class StrictBooleanField(BooleanField):
    def process_formdata(self, valuelist):
        self.data = None
        if valuelist:
            if valuelist[0] == 'false':
                self.data = False
            elif valuelist[0] == 'true':
                self.data = True


class StrictModelConverter(ModelConverter):
    @converts('Boolean')
    def conv_Boolean(self, field_args, **extra):
        return StrictBooleanField(**field_args)

MyForm = model_form(MyModel, db_session=db, converter=StrictModelConverter(),
           field_args = { 'disabled' : { 'validators': [BooleanRequired()] }
})

撰写回答