我正在寻找一种防止多个表单提交的通用方法。我发现这approach看起来很有希望。虽然我不希望在我的所有观点中都包含此代码段。使用请求处理器或中间件可能更容易做到这一点。
任何最佳做法建议?
答案 0 :(得分:13)
客户端,从JavaScript开始。你永远不能相信客户,但它是一个开始。
即。
onclick="this.disabled=true,this.form.submit();
服务器端你可以'将某些内容插入数据库,即校验和。如果它是一个插入数据库的记录,则使用model.objects.get_or_create()
来强制数据库级别的唯一性,你应该使用unique_together。
最后:HTTPRedirect是最好的,我在用户处理付款时使用的方法只是向感谢/确认页面发出HTTPRedirect()。这样刷新表单将不会重新提交,如果他们返回并尝试再次提交表单(不刷新表单),Django Cross Site Request Forgery(CSRF)将失败,完美!
答案 1 :(得分:1)
当用户dbl单击提交按钮时,我也试图找到一种防止生成双记录的好方法。 这与PRG问题无关,可以通过重定向轻松修复。
所以,关于这个基本问题,服务器端的HTTPRedirect解决方案没有帮助。
在客户端,我在提交前禁用按钮时发现了两个问题:
form.submit()
会被浏览器中断=>提交按钮仍为disabled=true
。disabled=true
。所以这是第一个客户端问题(HTML5验证)的解决方法:
isFormHtml5Valid(form) {
for(var el of form.querySelectorAll('input,textarea,select')){
if(!el.checkValidity())
return false;
}
return true;
}
mySubmitButton.onclick = function() {
if(this.form && isFormHtml5Valid(this.form))
this.disabled=true;
this.form.submit();
}
我试图找到第二个客户端问题(浏览器缓存DOM)的客户端解决方法,但没有任何工作(onbeforeunload,...)。 所以我目前用于"浏览器缓存的解决方法"问题是在相关视图的顶部添加@never_cache装饰(从服务器端,指示到客户端到不缓存)。如果您有更好的解决方法,请告诉我。
最后但并非最不重要,我真的很感谢在服务器端解决此问题。 CSRF解决方案似乎不适合CSRF token is generated by session(不适用于每种形式)。 所以这是我的工作状态和我的问题:
如果你有一个很好的解决方案,请告诉我。
编辑1: 可能只是答案的一小部分:Synchronizer (or Déjà vu) Token
但是我没有在Django中找到任何实现。
答案 2 :(得分:0)
使用 HttpResponseRedirect
创建一个新视图(比如thank_you
),以便在表单提交后显示成功的消息并返回模板。
成功提交表单后,将HttpResponseRedirect(“/ thank-you /”)返回到新的感谢视图
from django.http import HttpResponseRedirect
def thank_you(request, template_name='thank-you.html'):
return render_to_response(template_name,locals(),context_instance=RequestContext(request))
和urls.py
url(r'^thank-you/$','thank_you', name="thank_you")
多个表单提交发生是因为当页面刷新同一个url命中时,会一次又一次地调用同一个视图,因此会在数据库中保存多个条目。为防止这种情况发生,我们需要将响应重定向到新的网址/视图,以便下次页面刷新时会触及新的网址/视图。
答案 3 :(得分:0)
对于#2,最好在onsubmit
处理程序中执行此操作,而不是在提交按钮的onclick
中执行此操作。这将处理多个提交按钮等情况,或者是否有任何HTML5客户端表单验证。在jQuery中它看起来像:
$('#edit_form').submit( function(event) {
// disable to avoid double submission
$('#submit_button').attr('disabled', true);
});
但是,如果用户取消提交部分方式,则无法解决的一个问题。例如,如果您单击“提交”然后立即点击“Esc”,浏览器将停止提交,但“提交”按钮将被禁用。
此外,可以通过点击“输入”来提交表单,此解决方案不会阻止该表单提交两次。