我正试图找到一种方法来阻止用户双重提交表单。我有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
有人知道这是否已经存在?它似乎并不难写,所以如果它不存在我可以自己写。
答案 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。