2016-04-03 120 views
0

我想通过AJAX(只是JS,没有jQuery)上传HTML表单。表单由我的模板通过添加三个组件组装而成:csrf标记,ModelForm和常规Django表单(forms.Form)。模型表单{{form.as_p}}包含表单的可见部分,而{{order_form}}表单包含一些隐藏的字段。我的模板的形式部分看起来是这样的:Django后端FormData()对象总是空

<form id="{{ form_id }}" action="javascript:submitThisForm('{{ form_id }}', '/submit_blog_entry/')" method='POST' enctype='multipart/form-data'> 
     {% csrf_token %} 
     {{ form.as_p }} 
     {{ other_form }} 
     <input type='submit' value='SAVE changes' /> 
</form> 

我已经尝试从<form>标签删除加密类型(我在另一个问题的答复读取FORMDATA()自动将此),但无济于事。

当按下submit按钮时,调用JS函数submitBlodEntryForm(),传递表单ID和url以用于AJAX请求。该JS功能的代码在这里:

function submitThisForm(form_ID, url){ 

    var submit_form = document.getElementById(form_ID); 
    var formData = new FormData(document.getElementById(form_ID)); 

    httpRequest = new XMLHttpRequest(); 

    if (!httpRequest){ 
     alert("Giving up, cannot create an XMLHTTP instance."); 
     return false; 
    }; 

    var url = "/submit_blog_entry/"; 
    var sendCSRFtoken = "csrfmiddlewaretoken="+String(getCookie('csrftoken')); 
    var sendContent = sendCSRFtoken+"&"+formData; 

    httpRequest.onreadystatechange = alertContents; 
    httpRequest.open('POST', url, true); 
    httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
    //httpRequest.send(); 

    httpRequest.send(sendContent); 
    // alternatively: httpRequest.send(formData); 

} 

AJAX请求被提交给服务器并且被服务器接收(一个Django视图)。如果我没有手动添加上面的JS代码(变量sendContent)中显示的csrf标记并只发送formData,我会得到一个403错误,显然是因为服务器找不到标记。它应该是这样的形式,虽然部分...

当我接收到的数据绑定到相应的表单,验证失败:

form = ThisForm(request.POST) 
if form.is_valid(): 
    #do something 

如果我打印的内容是在request.POST,我在终端中获得以下内容:

<QueryDict: {'[object FormData]': [''], 'csrfmiddlewaretoken': ['token goes here']}> 

显然,FormData对象是空的。我还以为这是因为我得到两个必填字段以下两个错误在我的形式(通过使用form.errors.as_data()):

[ValidationError(['This field is required.'])] 

到底哪里出问题了?我搞乱了模板,FormData()不生成有用的数据吗?我错误地创建了AJAX请求吗?或者是服务器端的问题(尽管目前我几乎没有做任何事情)?

谢谢任何​​帮助,非常感谢!

回答

0

你有2个问题

  • 你必须使用FormData.append将数据添加到使用FORMDATA的请求。
  • FORMDATA对象使用在请求中的多部分/格式数据的内容类型(其被自动设置,并且正确地)
... 
var url = "/submit_blog_entry/"; 
formData.append("csrfmiddlewaretoken",getCookie('csrftoken')); 

httpRequest.onreadystatechange = alertContents; 
httpRequest.open('POST', url, true); 
//httpRequest.send(); 

httpRequest.send(formData); 
... 
+0

谢谢。我也尝试过,现在再次按照您的代码片段中的建议。也不起作用。即使我创建一个空的FormData()对象而不传递一个表单并添加它,csrf标记也不会通过(403错误再次出现)。 –

0

这可能是更好的形式元件不传递给FORMDATA这样的:

new FormData(document.getElementById(form_ID)) 

我几乎可以肯定,它只支持firefox。其他浏览器不会自动填充对象。

也是你做的事:

var sendContent = sendCSRFtoken+"&"+formData; 

由于“sendCSRFtoken”是一个字符串,它呼吁FORMDATA的toString()方法并连接了两下,就这就是为什么你会得到“[对象FORMDATA]” Django方面。

formData.append(name, value); 

做同样的CRSF令牌,然后调用发送这样的:使这项工作使用添加表单字段

一种方式

httpRequest.send(formData); 

的XMLHttpRequest具有发送多个重载所以你可以发送一个编码的字符串,如果你愿意的话:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()

这将是非常有用的,当调试时有网络选项卡在铬开放在排除客户端之前,在ajax调用前验证工具是否正确无误。

0

感谢大家。我现在发现这个问题,傻子复制&粘贴。创建AJAX请求的JS函数submitBlogEntryForm()很糟糕。设置httpRequest标头

httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 

引起了矛盾的编码指令。我只是完全删除了这一行,并且还避免在我的模板中的表单标记中指定“enctype”,并将所有这些都由FormData()自动设置。现在它工作了!

再次感谢您的帮助!