flask-bootstrap with two forms in one page

喜夏-厌秋 提交于 2019-11-30 18:27:55

问题


I plan to put two forms in one page in my flask app, one to edit general user information and the other to reset password. The template looks like this

{% 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 %} 

Each form has a submit button.

In the route function, I tried to separate the two form like this

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:
    .....

But it didn't work. When I click on the button in the ResetForm, the ProfileForm validation logic is executed.

I suspect the problem is that wtf.quick_form() creates two identical submit buttons, but not sure.

What should I do in this case? Can bootstrap/wtf.html template deal with this situation?


回答1:


Define this two SubmitField with different names, like this:

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

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

Then in 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 
....

Now the problem was solved.

If you want to dive into it, then continue read.

Here is 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()

And here is 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")

When you call form.validate_on_submit(), it check if form has been submitted by the HTTP method no matter which submit button was clicked. So the little trick above is just add a filter (to check if submit has data, i.e., form1.submit1.data).

Besides, we change the order of if, so when we click one submit, it only call validate() to this form, preventing the validation error for both form.

The story isn't over yet. Here is .data:

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

It return a dict with field name(key) and field data(value), however, our two form submit button has same name submit(key)!

When we click the first submit button(in form1), the call from form1.submit1.data return a dict like this:

temp = {'submit': True}

There is no doubt when we call if form1.submit.data:, it return True.

When we click the second submit button(in form2), the call to .data in if form1.submit.data: add a key-value in dict first, then the call from if form2.submit.data: add another key-value, in the end, the dict will like this:

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

Now we call if form1.submit.data:, it return True, even if the submit button we clicked was in form2.

That's why we need to define this two SubmitField with different names. By the way, thanks for reading(to here)!

Thanks for nos's notice, he add an issue about validate(), check the comments below!



来源:https://stackoverflow.com/questions/39738069/flask-bootstrap-with-two-forms-in-one-page

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!