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

Posted

技术标签:

【中文标题】FormData() 对象在 Django 后端始终为空【英文标题】:FormData() object is always empty in Django backend 【发布时间】:2016-07-23 07:45:00 【问题描述】:

我正在尝试通过 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>

我已经尝试从 &lt;form&gt; 标记中删除 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 视图)。如果我没有像上面的 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 请求?还是服务器端的问题(尽管到目前为止我几乎没有做任何事情)?

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

【问题讨论】:

【参考方案1】:

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

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

导致相互矛盾的编码指令。我刚刚完全删除了这一行,也没有在模板的表单标签中指定“enctype”,并将所有这些都由 FormData() 自动设置。现在可以了!

再次感谢您的帮助!

【讨论】:

【参考方案2】:

最好不要像这样将表单元素传递给 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 开发人员工具中打开网络选项卡以在排除客户端之前验证发布的内容是否正确,这将非常有帮助。

【讨论】:

喜欢关于网络标签的评论。这很有帮助!【参考方案3】:

你有两个问题

您必须使用 FormData.append 将数据添加到使用 Formdata 的请求中。 FormData对象在request中使用multipart/form-data内容类型(自动正确设置)
...
var url = "/submit_blog_entry/";
formData.append("csrfmiddlewaretoken",getCookie('csrftoken'));

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

httpRequest.send(formData);
...

【讨论】:

谢谢。按照您的代码 sn-p 中的建议,我之前和现在都尝试过。也不行。即使我创建了一个空的 FormData() 对象而不将表单传递给它然后附加它,csrf 令牌也不会通过(再次出现 403 错误)。

以上是关于FormData() 对象在 Django 后端始终为空的主要内容,如果未能解决你的问题,请参考以下文章

前端向后端发送请求(FormData)

如何查看formdata对象数据

JSON对象转成formData对象,formData对象转成JSON对象

JSON对象转成formData对象,formData对象转成JSON对象

FormData对象

将 FormData 对象读入 Java HTTP 触发的 Azure Functions