Prevent Multiple Form Submissions In Django
Solution 1:
Client side, start with JavaScript. You can never trust the client, but its a start.
i.e.
onclick="this.disabled=true,this.form.submit();
Server side you 'could' insert something into a database i.e. a checksum. If its a records you are insert into a database use model.objects.get_or_create()
to force the uniqueness on database level you should use unique_together.
Lastly: HTTPRedirect is best, The the method I use when a user processes a payment is to just issue a HTTPRedirect() to the thank you/conformation page. This way refreshing the form won't resubmit and if they go back and try to submit the form again (without refreshing the form) the Django Cross Site Request Forgery (CSRF) will fail, perfect!
Solution 2:
I also try to find a good way to prevent double records generation when a user dbl-click on a submit button. It's not about the PRG issue that is easily fixed by redirection.
So, regards on this basic concern, the solution with HTTPRedirect on server-side doesn't help.
On client-side, I found two problems when I disable the button before submit:
- With HTML5 validation, the
form.submit()
will be interupted by browser if the form is invalid => submit button is stilldisabled=true
. - When the user submit the form and do a back in browser history, the DOM will be loaded from browser's cache => submit button is still
disabled=true
.
So here is my workaround for the first client-side problem (HTML5 validation):
isFormHtml5Valid(form) {
for(var el of form.querySelectorAll('input,textarea,select')){
if(!el.checkValidity())
returnfalse;
}
returntrue;
}
mySubmitButton.onclick = function() {
if(this.form && isFormHtml5Valid(this.form))
this.disabled=true;
this.form.submit();
}
I try to find a client-side workaround for the second client-side problem (browser cache the DOM) but nothing worked (onbeforeunload, ...). So the workaround I currently use for "browser cache" issue is add a @never_cache decoration on the top of concerned views (from server-side, indicate to client-side to not caching). Please let me know if you have a better workaround.
Last but not least, I would really appreciate to fix this issue on server side. The CSRF solution seems not suitable since a CSRF token is generated by session (not for each form). So here is the status of my work and my question:
- Fix this issue on client-side is OK but doesn't look like a good solution to me. How could we avoid to validate this multiple form submition on server-side?
Let me know if you have a good solution for that.
Edit 1: May be a small part of the answer: Synchronizer (or Déjà vu) Token
But I didn't find any implemantation of that in Django.
Solution 3:
Use HttpResponseRedirect
create a new view(lets say thank_you
) for successful message to display after form submission and return a template.
After successful form submission do return HttpResponseRedirect("/thank-you/") to the new thank-you view
from django.http import HttpResponseRedirect
defthank_you(request, template_name='thank-you.html'):
return render_to_response(template_name,locals(),context_instance=RequestContext(request))
and in urls.py
url(r'^thank-you/$','thank_you', name="thank_you")
Multiple form submission happens because when page refreshes that same url hits, which call that same view again and again and hence multiple entries saved in database. To prevent this, we are required to redirect the response to the new url/view, so that next time page refreshes it will hit that new url/view.
Solution 4:
- After a successful submission respond with a redirect so a reload doesn't cause another submission
- Disable the submit button on form submission
As for #2, it's best to do that in the onsubmit
handler and not the onclick
for the submit button. This will handle cases such as multiple submit buttons or if there's any HTML5 client-side form validation. In jQuery it'd look something like:
$('#edit_form').submit( function(event) {
// disable to avoid double submission
$('#submit_button').attr('disabled', true);
});
However, one issue this doesn't account for is if the user cancels the submit part way. For example, if you click "submit" and then immediately hit "Esc", the browser will stop the submission but "submit" button will already be disabled.
Also, it's possible to have a form that is submitted by hitting "enter" and this solution wouldn't prevent that form from submitting twice.
Post a Comment for "Prevent Multiple Form Submissions In Django"