Flask问题集:单个页面两个(多个)表单

出于简化交互的考虑,我们经常见到很多网站把登录页面和注册界面放在同一个页面上,而当我们使用Flask来实现时,却发现问题重重:

  • 不管是哪个表单按下了提交按钮,总是提交第一个表单的数据;
  • 当一个表单数据验证出错时,两个表单都出现了错误提示;

问题的解决

简单来说,问题的主要原因是Flask-WTF的form1.validate_on_submit()并不验证是哪个表单的submit按钮被按下了,只是通过HTTP方法是否是“PUT”或“POST”来判断。

同时form1.submit1.data的data函数会迭代字段的名字(submit)和数据(True/False)作为一个字典,这会产生键重复的问题,所以确保两个表单的submit字段的名字不同。

另外,更改if语句判断条件的顺序(只对按下按钮的表单执行.validate_on_submit()),避免一个表单出错时两个表单同时出现错误提示信息。具体见下面两个代码块。

为你的不同表单里的SubmitField定义不同的名字,像这样:

在 view.py 里添加if判断:

现在问题解决了,如果你想了解更多一点,那就继续读下去。

探究问题的本质

这是 validate_on_submit():

这是 is_submitted():

当你对表单调用 form.validate_on_submit() 的时候,它只是通过HTTP方法来检查提交的表单,而不是哪个表单上的按钮被按下了。所以上面的小技巧只是添加一个过滤器(也就是检查按钮是不是有数据,即 form1.submit.data)。

另外,我们改变了if判断的顺序。这样当我们点击其中一个表单上的按钮时,它只对这个表单调用验证函数validate(),所以不会两个表单都出现错误提示。

故事还没完,这是静态方法.data:

它返回一个以字段名(field name)和字段值(field value)作为键值对的字典,但要注意的是,两个表单的提交按钮的字段名都是submit!

这带了什么问题呢?想一想Python里字典的特性就知道了,字典用键来索引一个值,所以会有键重复的问题。

当我们点击第一个表单上的提交按钮(submit)时,form1.submit1.data返回一个像这样的字典:

毫无疑问,当我们调用 if form1.submit.data时,它会返回True。

而当我们点击第二个表单上的提交按钮(也是submit)时,if form1.submit.data先生成了一个键值对,然后form2.submit.data生成了键值对,结果这个字典就变成了这样:

这就是为什么我们不论点击那个表单上的按钮,对第一个表单的验证总是返回True。我们通过为两个表单的字段设定不同的名字解决了这个问题。

感谢你读到这里,这样看来,你有很强的好奇心和耐心,而且对编程怀有很大的热情,我说的没错吧:p

首发于Stack Overflow:python – flask-bootstrap with two forms in one page

更多关于Flask的优质内容,欢迎关注Hello, Flask! – 知乎专栏

Flask问题集:单个页面两个(多个)表单》上有2条评论

  1. 赫伟

    你好,按照你的方法我设置了多个submit都有唯一name属性,但是没效果
    我尝试着print from.submit.date 这个值一直为false,而且 打印request.form发现其中不包含submit相关的值
    所以不论是一个页面多个表单,还是一个表单多个submit我都实现不了,这个是什么原因啊

    回复

说说你的想法吧!

邮箱不会被公开,必填项已用*标出。

*

*