I have multiple form on the same page that send post request to same handler in flask.
I am generating forms using wtforms.
what is the best way to identify which form is submitted ?
I am currently using action="?form=oneform"
. I think there should be some better method
to achieve the same?
The solution above have a validation bug, when one form cause a validation error, both forms display an error message. I change the order of
if
to solve this problem.First, define your multiple
SubmitField
with different names, like this:Then add a filter in
view.py
:Now the problem was solved.
If you want to dive into it, then continue read.
Here is
validate_on_submit()
:And here is
is_submitted()
:When you call
form.validate_on_submit()
, it check if form is 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 callvalidate()
to this form, preventing the validation error for both form.The story isn't over yet. Here is
.data
: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:There is no doubt when we call
if form1.submit.data:
, it returnTrue
.When we click the second submit button(in form2), the call to
.data
inif form1.submit.data:
add a key-value in dict first, then the call fromif form2.submit.data:
add another key-value, in the end, the dict will like this:Now we call
if form1.submit.data:
, it returnTrue
, 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)!Update
There is another way to handle multiple forms on one page. You can use multiple views to handle forms. For example:
In the template (index.html), you need to render both forms and set the
action
attribute to target view:A simple way is to have different names for different submit fields. For an example:
forms.py:
views.py:
I've been using a combination of two flask snippets. The first adds a prefix to a form and then you check for the prefix with validate_on_submit(). I use also Louis Roché's template to determine what buttons are pushed in a form.
To quote Dan Jacob:
Example:
Then, add a hidden field (or just check a submit field):
To quote Louis Roché's:
I have in my template :
And to figure out which button was passed server side I have in my views.py file:
As the other answers, I also assign a unique name for each submit button, for each form on the page.
Then, the flask web action looks like below - note the
formdata
andobj
parameters, which help to init / preserve the form fields accordingly: