I am trying to implement a server-side check to prevent users from double-submitting my forms (Django web app).
One technique I'm trying is:
1) When the form is created, save a unique ID in the session, plus pass the unique ID value into the template as well.
2) When the form is submitted, pop the unique ID from the session, and compare it to the same unique ID retrieved from the form.
3) If the values are the same, allow processing, otherwise not.
These SO answers contributed in me formulating this.
Here's a quick look at my generalized code:
def my_view(request):
if request.method == 'POST':
secret_key_from_form = request.POST.get('sk','0')
secret_key_from_session = request.session.pop('secret_key','1')
if secret_key_from_form != secret_key_from_session:
return render(request,"404.html",{})
else:
# process the form normally
form = MyForm(request.POST,request.FILES)
if form.is_valid():
# do something
else:
# do something else
else:
f = MyForm()
secret_key = uuid.uuid4()
request.session["secret_key"] = secret_key
request.session.modified = True
return render(request,"my_form.html",{'form':f,'sk':secret_key})
And here's a sample template:
<form action="{% url 'my_view' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="sk" value="{{ sk }}">
{{ form.my_data }}
<button type="submit">OK</button>
</form>
This set up has failed to stop double-submission.
I.e., one can go on a click frenzy and still end up submitting tons of copies. Moreover, if I print secret_key_from_form
and secret_key_from_session
, I see them being printed multiple times, even though secret_key_from_session
should have popped after the first attempt.
What doesn't this work? And how do I fix it?
UPDATE: when I use redis cache to save the value of the special key, this arrangement works perfectly. Therefore, it seems the culprit is me being unable to update request.session
values (even with trying request.session.modified=True
). I'm open to suggestions vis-a-vis what could be going wrong.
Note that this question specifically deals with a server-side solution to double-submission - my JS measures are separate and exclusive to this question.