django是否存在防止重复表单提交的库?

时间:2010-01-26 01:10:52

标签: python django code-reuse

我正试图找到一种方法来阻止用户双重提交表单。我有javascript禁用提交按钮,但仍然有偶尔的用户找到双重提交的方法。

我有一个可重复使用的库的愿景,我可以创建以防止这种情况。

在我理想的库中,代码块看起来像这样:

try:
    with acquire_lock({'field1':'abc', 'field2':'def'}) as lock:
        response = #do some credit card processing
        lock.response = response
except SubmissionWasDuplicate, e:
    response = e.response

锁表看起来像这样:

duplicate_submission_locks

  • submission_hash#提交参数的MD5
  • 响应#pickled数据
  • created_at#用于扫描此表
  • lock_expired#boolean表示锁是否已过期

有人知道这是否已经存在?它似乎并不难写,所以如果它不存在我可以自己写。

5 个答案:

答案 0 :(得分:11)

您可以使用会话来存储哈希

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() 

使用这种方法(不删除会话cookie),用户无法重新存储会话过期的数据,顺便说一句,我假设存在识别发送数据的用户的东西

答案 1 :(得分:6)

解决此问题的一个简单方法是为每个表单添加一个唯一的哈希值。然后你可以有一个当前表格的滚动表。提交表单或者哈希值太旧时,您可以将其从表中过期,并拒绝表中没有匹配哈希的任何表单。

HTTPRedirect是正确的方法,如前所述。

不幸的是,即使Django自己的内置管理员也容易出现与此问题相关的问题。在某些情况下,跨站点脚本框架可以帮助防止其中的一些,但我担心当前的生产版本没有内置。

答案 2 :(得分:4)

老实说,你最好的选择(简单和良好的练习)是向感谢页面发出HTTPRedirect(),如果感谢页面与表单相同,那就没问题。你仍然可以这样做。

答案 3 :(得分:3)

克里斯蒂安·达米安的回答真是一个很好的建议。我只是想到了这个主题的微小变化,但它可能会有更多的开销。

您可以尝试在django-piston中为BaseHandler对象实现一些内容,这是一种名为exists()的方法,用于检查您提交的内容是否已存在于数据库中。

来自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

所以让我们说这是一个名为request_exists()的函数,而不是方法:

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

答案 4 :(得分:2)

使用postirect-after-post方法总是好的。这可以防止用户意外地使用浏览器中的刷新功能重新提交表单。即使使用哈希方法,它也很有用。这是因为在POST后没有重定向,如果点击后退/刷新按钮,用户将看到有关重新提交表单的问题消息,这可能会使她感到困惑。

如果你在每次POST后都进行GET重定向,那么点击Back / Refresh将不会显示这个wierd(对于普通用户)的消息。因此,对于完全保护,请使用Hash + postirect-after-post。