我正在尝试通过AJAX上传HTML表单(只是JS,没有jQuery)。表单由我的模板通过添加三个组件来组装:csrf标记,ModelForm和常规Django表单(forms.Form)。模型表单{{form.as_p}}包含表单的可见部分,而表单{{order_form}}包含一些隐藏字段。我的模板的表单部分如下所示:
<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>
标记中删除enctype(我在回复另一个问题时读到了FormData()自动添加),但无济于事。
当按下提交按钮时,将调用JS函数submitBlodEntryForm(),传递表单ID和用于AJAX请求的URL。这个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视图)。如果我没有手动添加csrf令牌,如上面的JS代码(变量sendContent)所示,只是发送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 :(得分:0)
你有2个问题
...
var url = "/submit_blog_entry/";
formData.append("csrfmiddlewaretoken",getCookie('csrftoken'));
httpRequest.onreadystatechange = alertContents;
httpRequest.open('POST', url, true);
//httpRequest.send();
httpRequest.send(formData);
...
答案 1 :(得分:0)
最好不要将表单元素传递给FormData,如下所示:
new FormData(document.getElementById(form_ID))
我几乎可以肯定,它只受到firefox的支持。其他浏览器不会自动填充对象。
您也可以这样做:
var sendContent = sendCSRFtoken+"&"+formData;
因为&#39; sendCSRFtoken&#39;是一个字符串,它调用formData上的toString()方法并连接这两个,这就是为什么你得到&#39; [object FormData]&#39;在django一侧。
使用此功能的一种方法是使用以下方法添加表单字段:
formData.append(name, value);
对CRSF令牌执行相同操作,然后像这样调用send:
httpRequest.send(formData);
XMLHttpRequest有多个发送重载,因此如果您愿意,也可以发送编码字符串:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()
在进行调试之前,在ajax调用之前在chrome开发人员工具中打开网络选项卡,以便在排除客户端之前验证发布的内容是否正确,这将非常有用。
答案 2 :(得分:0)
感谢大家。我现在发现了问题,愚蠢的复制和粘贴。创建AJAX请求的JS函数submitBlogEntryForm()很糟糕。设置httpRequest标头
httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
导致编码指令矛盾。我只是完全删除了这一行,并且还避免在我的模板中的form标签中指定“enctype”,并将所有这些保留为FormData()自动设置。现在它有效!
再次感谢您的帮助!