在Django后端,FormData()对象始终为空

FormData() object is always empty in Django backend

本文关键字:对象 Django 后端 FormData      更新时间:2023-11-23

我正试图通过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(),传递用于AJAX请求的表单ID和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视图)。如果我没有手动添加上面JS代码中所示的csrf令牌(变量sendContent),只发送formData,我会收到403错误,显然是因为服务器找不到令牌。它应该是形式的一部分,不过。。。

当我尝试将收到的数据绑定到相应的表单时,验证失败:

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

如果我打印所需内容。POST,我在终端中得到以下内容:

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

显然,FormData对象是空的。我之所以这么认为,是因为我的表单中的两个必填字段(通过使用form.errors.as_data())出现了以下两个错误:

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

出了什么问题?我是否把模板搞砸了,以至于FormData()无法生成有用的数据?我是否错误地创建了AJAX请求?还是服务器端的问题(尽管到目前为止我几乎没有在那里做任何事情)?

谢谢你,非常感谢你的帮助!

最好不要像这样将表单元素传递给FormData:

new FormData(document.getElementById(form_ID))

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

还有你做的:

var sendContent = sendCSRFtoken+"&"+formData;

由于"sendCSRFtoken"是一个字符串,它调用formData上的toString()方法并将两者连接起来,这就是为什么在django端获得"[object formData]"的原因。

使这项工作添加表单字段的一种方法是:

formData.append(name, value);

对CRSF令牌执行同样的操作,然后调用send,如下所示:

httpRequest.send(formData);

XMLHttpRequest有多个用于发送的重载,因此如果您愿意,也可以发送编码字符串:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()

在调试时,在ajax调用之前在chrome开发工具中打开网络选项卡,以验证发布的内容是否正确,然后再排除客户端,这将非常有帮助。

感谢大家。我现在发现了问题,愚蠢的复制&粘贴创建AJAX请求的JS函数submitBlogEntryForm()不正确。设置httpRequest标头

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

导致与编码指令相矛盾。我只是完全删除了这一行,也没有在模板的表单标记中指定"enctype",而是让FormData()自动设置所有这些。现在它工作了!

再次感谢您的帮助!

有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);
...