6👍
One easy solution to this problem is to add a unique hash to each form. Then you can have a rolling table of current forms. When a form is submitted, or the hash gets too old, you can expire it out of your table, and reject any form which does not have a matching hash in your table.
The HTTPRedirect is the correct way to do it, as previously mentioned.
Unfortunately, even Django’s own built in admin is prone to problems related to this issue. In some cases, the cross-site scripting framework can assist to prevent some of this, but I’m afraid the current production versions just don’t have this built in.
12👍
You can use a session to store the hash
import hashlib
def contact(request):
if request.method == 'POST':
form = MyForm(request.POST)
#join all the fields in one string
hashstring=hashlib.sha1(fieldsstring)
if request.session.get('sesionform')!=hashstring:
if form.is_valid() :
request.session['sesionform'] = hashstring
#do some stuff...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else
raise SubmissionWasDuplicate("duplicate")
else:
form = MyForm()
With this approach (not deleting the session cookie) the user can’t re-store the data util the session expires, by the way, i’m assuming that exist something who identify the user who send the data
- Reset SQLite database in Django
- Tastypie Negation Filter
- Django create new user without password
- Django makemigrations not detecting project/apps/myapp
- Csrf error in django
3👍
To be honest, your best bet (easy and good practice) is to issue a HTTPRedirect() to the thank you page, and if the thank you page is the same one as the form, that’s OK. You can still do this.
3👍
Kristian Damian’s answer is really a great suggestion. I just thought of a slight variation on that theme, but it might have more overhead.
You could try implementing something that is used in django-piston for BaseHandler
objects, which is a method called exists()
that checks to see if what you are submitting is already in the database.
From handler.py (BaseHandler):
def exists(self, **kwargs):
if not self.has_model():
raise NotImplementedError
try:
self.model.objects.get(**kwargs)
return True
except self.model.DoesNotExist:
return False
So let’s say make that a function called request_exists()
, instead of a method:
if form.is_valid()
if request_exists(request):
# gracefully reject dupe submission
else:
# do stuff to save the request
...
# and ALWAYS redirect after a POST!!
return HttpResponseRedirect('/thanks/')
- How to disable request logging in Django and uWSGI?
- Django render_to_string() ignores {% csrf_token %}
- (gcloud.app.deploy) Error Response: [7] Access Not Configured. Cloud Build has not been used in project
- Logging formatters in django
- Session authentication with Django channels
2👍
It is always good to use the redirect-after-post method. This prevents user from accidently resubmitting the form using refresh function from the browser. It is also helpful even when you use the hash method. It’s because without redirect after a POST, in case of hitting Back/Refresh button, user will see a question message about resubmitting the form, which can confuse her.
If you do a GET redirect after every POST, then hitting Back/Refresh won’t display this wierd (for usual user) message. So for full protection use Hash+redirect-after-post.
- Colorizing the output of Django tests
- Creating Partial Indexes with Django 1.7
- Django aggregation: sum then average
- Django database synchronization for an offline usage