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

18 投票
5 回答
8390 浏览
提问于 2025-04-15 18:28

我想找个办法来防止用户重复提交我的表单。我已经用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值
  • response # 序列化的数据
  • created_at # 用于清理这个表
  • lock_expired # 一个布尔值,表示锁是否过期

有没有人知道这个东西是否已经存在?看起来写起来并不难,如果没有的话,我可能会自己写一个。

5 个回答

3

老实说,最简单也最好的做法就是用 HTTPRedirect() 方法跳转到感谢页面。如果感谢页面和表单是同一个页面,那也没问题,你照样可以这样做。

12

你可以用一个会话来存储哈希值。

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),用户在会话过期之前无法重新存储数据。顺便说一下,我假设有某种方式可以识别发送数据的用户。

6

解决这个问题的一个简单方法是给每个表单添加一个独特的哈希值。这样,你就可以有一个当前表单的滚动列表。当一个表单被提交,或者哈希值过期时,你可以把它从列表中移除,并拒绝任何没有匹配哈希值的表单。

使用HTTP重定向是正确的做法,正如之前提到的那样。

不幸的是,连Django自带的管理后台也会遇到与这个问题相关的麻烦。在某些情况下,跨站脚本的框架可以帮助防止一些问题,但我担心目前的生产版本并没有内置这个功能。

撰写回答