在项目里使用 wtforms,设置了一个带默认值的 StringField,但提交表单如果没有这项或值是空的,则返回为空,并不会使用 default 里的值
例如定义如下表单
def ListForm(Form): status = StringField("status", validators=[Optional()], default="all")
提交一个空请求,返回的 status 是空而不是 all。去跟代码并看了下 GitHub 上的 issue 讨论,按 wtforms 官方的说法,这是故意设计成这样的,参考如下内容
- StringField default value does not work #225
- http://wtforms.readthedocs.io/en/latest/faq.html#why-does-blank-input-not-go-back-to-the-default-value
大意是,如果用户设置了一个 Field,那么他就应该有值,不然我们就强行设置为空
但是这个逻辑狗屁不通,因为除了 StringField 其他的类型域就没这个问题,比如 IntegerField 就是可以这么用而且能返回正确的 default
def ListForm(Form): status = StringField("status", validators=[Optional()], default="all") x = IntegerField("x", validators=[Optional()], default=9)
没办法自己新增了一个 StringFieldWithDefault 的类来解决这个问题(被覆盖的代码可以看上面 GitHub Issue 里的讨论)
class StringFieldWithDefault(StringField): def process_formdata(self, valuelist): if valuelist: self.data = valuelist[0] else: self.data = self.object_data
而且 wtforms 的数据校验也是谜一般的逻辑,比如设置如下
def ListForm(Form): status = StringField("status", validators=[Optional(), AnyOf(["all", "visible"])], default="all") x = IntegerField("x", validators=[DataRequired()])
这里会出现两个问题
一是 Optional 如果发现没有值或空,是能通过这个校验的,这里逻辑也没错,但是特喵的 Optional 如果遇到值为空的时候,会把之前的所有错误都清空,并且停止检查后面的 validator。这个迷一般的逻辑会导致如果传的空字段,即没有按正常人预期的拿到 default,也没有去执行 AnyOf 的校验,而是直接通过了。这个官方无解,也不打算修,只说在 3.x 的时候考虑加配置参数,不过看进度上一个版本已经是 2015 年发布的 2.1,而且 GitHub 仓库并不活跃,那么只能呵呵呵呵,然后换自己的 StringFieldWithDefault 吧
二是 DataRequired 不是检查 if field.name in formdata
,而是检查 if field.data
,这就意味着,如果传了一个 0 的整型参数给 IntegerField,是通不过 DataRequired 的验证的,同理还有空字符串。这个可以改用 InputRequired 来解决,还算是官方给了条活路