[Fixed]-Does a library to prevent duplicate form submissions exist for django?

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

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/') 

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.

Leave a comment