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?
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With