【问题标题】:WTForms-JSON with optional nesting using FormFieldWTForms-JSON 使用 FormField 进行可选嵌套
【发布时间】:2014-01-09 21:54:35
【问题描述】:

我正在使用WTForms-JSON 并处理嵌套表单。我想将内部表单设为可选,但如果存在内部表单,我希望它的字段是必需的。我遇到的问题是FormField 不接受验证器。

(虽然我使用的是 WTForms-JSON,但我相信这也适用于原版 WTForms。)

此代码有效,但不符合我的要求:

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

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

上面代码的问题是inner 是隐式需要的。奇怪的是,当inner 被省略时validate() 返回Falseerrors 是空的。

此代码不起作用:

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

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

后者产生这个错误:

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

我的问题是:如何使inner 可选,但如果inner 存在则需要foo_id

【问题讨论】:

    标签: wtforms wtforms-json


    【解决方案1】:

    最简单的方法是将FormField 包装在FieldList 中,将max_entries 设置为1。FieldList 也支持验证器,但由于min_entries 默认为0,因此您不需要任何验证器。唯一令人烦恼的是,如果内部表单的数据可用,您将不得不对其进行解包。

    【讨论】:

    • +1 是一个很好的建议,但不幸的是,它会更改 API 并需要客户端更改或服务器端预处理来调整数据结构,这对我来说都不是一个好的选择。我可能只是修补 WTForms 以使 FormField() 尊敬 Required()Optional()
    • @JimStewart - 很公平。绝对值得一个拉取请求,因为他们现在正在开发 WTForms 2.0 :-)
    • 我接受这个,因为我想要的东西不支持,这是一个很好的解决方法。如果我有时间修补 WTForms,我会在这里更新。
    【解决方案2】:

    感谢@aryeh 提供OptionalFormField。我只是把我稍微改进的(在我看来)版本放在这里:

    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
    

    【讨论】:

      【解决方案3】:

      如果有人来这里寻找解决方案,这里有一个简单的方法:

      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
      

      它的作用是只有在表单数据中找到与该表单相关的键时才运行表单验证。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-12
        • 2018-05-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多