防止Django中的多个表单提交

时间:2013-03-27 23:12:20

标签: python django forms hash

我正在寻找一种防止多个表单提交的通用方法。我发现这approach看起来很有希望。虽然我不希望在我的所有观点中都包含此代码段。使用请求处理器或中间件可能更容易做到这一点。

任何最佳做法建议?

4 个答案:

答案 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解决方案没有帮助。

在客户端,我在提交前禁用按钮时发现了两个问题:

  1. 使用HTML5验证,如果表单无效,则form.submit()会被浏览器中断=>提交按钮仍为disabled=true
  2. 当用户提交表单并在浏览器历史记录中返回时,将从浏览器的缓存中加载DOM =>提交按钮仍为disabled=true
  3. 所以这是第一个客户端问题(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)

  1. 成功提交后,使用重定向进行响应,以便重新加载不会导致其他提交
  2. 停用表单提交上的提交按钮
  3. 对于#2,最好在onsubmit处理程序中执行此操作,而不是在提交按钮的onclick中执行此操作。这将处理多个提交按钮等情况,或者是否有任何HTML5客户端表单验证。在jQuery中它看起来像:

    $('#edit_form').submit( function(event) {
        // disable to avoid double submission
        $('#submit_button').attr('disabled', true);
    });
    

    但是,如果用户取消提交部分方式,则无法解决的一个问题。例如,如果您单击“提交”然后立即点击“Esc”,浏览器将停止提交,但“提交”按钮将被禁用。

    此外,可以通过点击“输入”来提交表单,此解决方案不会阻止该表单提交两次。