【问题标题】:flask-bootstrap with two forms in one page一页有两种形式的烧瓶引导程序
【发布时间】:2017-02-05 21:02:40
【问题描述】:

我打算在我的烧瓶应用程序的一个页面中放置两个表单,一个用于编辑一般用户信息,另一个用于重置密码。模板是这样的

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block page_content %}                                                   
<div class="page-header">                                                  
    <h1>Edit Profile</h1>
</div>

{{ wtf.quick_form(form_profile, form_type='horizontal') }}                 

<hr>

{{ wtf.quick_form(form_reset, form_type='horizontal') }}                   

<hr>
{% endblock %} 

每个表单都有一个提交按钮。

在路由函数中,我尝试将这两种形式分开

form_profile = ProfileForm()
form_reset = ResetForm()

if form_profile.validate_on_submit() and form_profile.submit.data:
    ....
if form_reset.validate_on_submit() and form_reset.submit.data:
    .....

但它没有用。当我单击 ResetForm 中的按钮时,会执行 ProfileForm 验证逻辑。

我怀疑问题在于wtf.quick_form() 创建了两个相同的提交按钮,但不确定。

在这种情况下我该怎么办? bootstrap/wtf.html模板可以处理这种情况吗?

【问题讨论】:

    标签: python flask flask-wtforms flask-bootstrap


    【解决方案1】:

    用不同的名字定义这两个SubmitField,像这样:

    class Form1(Form):
        name = StringField('name')
        submit1 = SubmitField('submit')
    
    class Form2(Form):
        name = StringField('name')
        submit2 = SubmitField('submit')
    

    然后在view.py:

    ....
    form1 = Form1()
    form2 = Form2()
    
    if form1.submit1.data and form1.validate_on_submit():  # notice the order 
    ....
    if form2.submit2.data and form2.validate_on_submit():  # notice the order 
    ....
    

    现在问题解决了。

    如果您想深入了解,请继续阅读。

    这里是validate_on_submit()

        def validate_on_submit(self):
            """
            Checks if form has been submitted and if so runs validate. This is
            a shortcut, equivalent to ``form.is_submitted() and form.validate()``
            """
            return self.is_submitted() and self.validate()
    

    这里是is_submitted():

        def is_submitted(self):
            """
            Checks if form has been submitted. The default case is if the HTTP
            method is **PUT** or **POST**.
            """
    
            return request and request.method in ("PUT", "POST")
    

    当您调用form.validate_on_submit() 时,无论点击哪个提交按钮,它都会检查是否已经通过HTTP 方法提交了表单。所以上面的小技巧就是添加一个过滤器(检查提交是否有数据,即form1.submit1.data)。

    另外,我们改变了 if 的顺序,所以当我们点击一​​个提交时,它只调用这个表单的 validate(),防止两个表单的验证错误。

    故事还没有结束。这里是.data

    @property
    def data(self):
        return dict((name, f.data) for name, f in iteritems(self._fields))
    

    它返回一个带有字段名称(键)和字段数据(值)的字典,但是,我们的两个表单提交按钮具有相同的名称submit(键)!

    当我们点击第一个提交按钮(在 form1 中)时,来自form1.submit1.data 的调用会返回一个这样的字典:

    temp = {'submit': True}
    

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

    当我们点击第二个提交按钮(在form2中)时,if form1.submit.data:中对.data的调用在dict中添加一个键值首先,然后来自if form2.submit.data:的调用添加另一个键值,最后,dict会是这样的:

    temp = {'submit': False, 'submit': True}
    

    现在我们调用if form1.submit.data:,它返回True,即使我们点击的提交按钮在form2中。

    这就是为什么我们需要用不同的名字定义这两个SubmitField。顺便说一句,感谢阅读(到这里)!

    感谢nos的通知,他添加了一个关于validate()的issue,查看下面的cmets!

    【讨论】:

    • 感谢您的提示。我还注意到 and form1.submit1.data 不再需要了。
    • 不客气,但我虽然需要and form1.submit1.data,但可以删除第二个过滤器form2.submit2.data。我更新了答案。
    • 再次感谢您的详细解释。我注意到还有一个问题:当第一个表单的验证失败时,两个表单的错误消息都会出现,这让用户感到困惑,因为他们可能认为两个表单都需要填写。问题是表单验证总是为第二个表单调用。可以通过更改if中的逻辑来解决,即if form2.submit2.data and form2.validate_on_submit() :。那么如果表单没有提交,它就不会被验证。
    猜你喜欢
    • 2021-03-29
    • 2012-06-27
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多