简体   繁体   English

WTForms-JSON,使用FormField可选嵌套

[英]WTForms-JSON with optional nesting using FormField

I'm using WTForms-JSON and processing nested forms. 我正在使用WTForms-JSON并处理嵌套表单。 I'd like to make an inner form optional, but if the inner form is present, I'd like its fields to be required. 我想使内部表单可选,但如果内部表单存在,我希望它的字段是必需的。 The problem I'm running into is that FormField doesn't accept validators. FormField的问题是FormField不接受验证器。

(Although I'm using WTForms-JSON, I believe this applies to vanilla WTForms as well.) (虽然我使用的是WTForms-JSON,但我相信这也适用于vanilla WTForms。)

This code works but doesn't behave the way I want: 此代码有效,但不按我想要的方式运行:

class InnerForm(Form):
    foo_id = IntegerField("Foo ID", [Required()])

class OuterForm(Form):
    inner = FormField(InnerForm)

The problem with the above code is that inner is implicitly required. 上面代码的问题是inner隐是隐式需要的。 Oddly, while validate() returns False when inner is omitted, errors is empty. 奇怪的是,当省略inner时, validate()返回Falseerrors为空。

This code doesn't doesn't work: 此代码不起作用:

class InnerForm(Form):
    foo_id = IntegerField("Foo ID", [Required()])

class OuterForm(Form):
    inner = FormField(InnerForm, "Inner", [Optional()])

The latter produces this error: 后者产生此错误:

TypeError: FormField does not accept any validators. Instead, define them on the enclosed form.

My question is: how can I make inner optional, but require foo_id if inner is present? 我的问题是:如何使inner可选,但如果inner存在则需要foo_id

The easiest way is to wrap the FormField in a FieldList , with max_entries set to 1. FieldList also supports validators, but since min_entries is 0 by default you should not need any. 最简单的方法是将FormField包装在FieldList ,并将max_entries设置为1. FieldList也支持验证器,但由于min_entries默认为0,因此您不需要任何验证器。 The only annoyance will be that you will have to unwrap the inner form's data if it is available. 唯一的烦恼是,如果内部表格的数据可用,您必须打开它。

In case anyone comes here looking for a solution to this, here is a simple one: 如果有人来这里寻找解决方案,这里有一个简单的方法:

from wtforms.fields import FormField, _unset_value

class OptionalFormField(FormField):

    def process(self, formdata, data=_unset_value):
        self._formdata = formdata
        return super(OptionalFormField, self).process(formdata, data=data)

    def validate(self, form, extra_validators=tuple()):
        if extra_validators:
            raise TypeError('FormField does not accept in-line validators, as it gets errors from the enclosed form.')

        # Run normal validation only if there is data for this form
        for field_name in self._formdata.keys():
            if field_name.find(self.name) == 0:
                return self.form.validate()

        return True

What this does is it only runs the form validation if it finds keys in the formdata that pertain to that form. 这样做只是在它找到与该表单相关的formdata中的键时才运行表单验证。

Thanks @aryeh for OptionalFormField . 感谢@aryeh for OptionalFormField I just put here my slightly improved (in my opinion) version: 我只是把我的略有改进(在我看来)版本放在这里:

class OptionalFormField(FormField):

    def process(self, formdata, *args, **kwargs):
        self._formdata = formdata
        return super(OptionalFormField, self).process(formdata, *args, **kwargs)

    def validate(self, *args, **kwargs):
        if self._formdata:
            for field_name in self._formdata.keys():
                if field_name.startswith(self.name + self.separator):
                    return super(OptionalFormField, self).validate(*args, **kwargs)
        return True

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM