简体   繁体   English

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

[英]FormData() object is always empty in Django backend

I am trying to upload an HTML form via AJAX (just JS, no jQuery). 我正在尝试通过AJAX(只是JS,没有jQuery)上传HTML表单。 The form is assembled by my template by adding three components: The csrf token, a ModelForm and a regular Django form (forms.Form). 通过添加三个组件,该模板由我的模板组装而成:csrf令牌,ModelForm和常规Django表单(forms.Form)。 The model form {{ form.as_p}} comprises the visible parts of the form whereas the form {{ order_form }} comprises some hidden fields. 模型表单{{form.as_p}}包含表单的可见部分,而表单{{order_form}}包含一些隐藏字段。 The form section of my template looks like this: 我的模板的表单部分如下所示:

<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>

I already tried to remove enctype from the <form> tag (I read in a reply to another question that FormData() adds this automatically), but to no avail. 我已经尝试从<form>标记中删除enctype(我读了一个对FormData()自动添加此问题的回答),但无济于事。

When the submit button is pressed, the JS function submitBlodEntryForm() is called, passing the form ID and the url to use for the AJAX request. 当按下提交按钮时,将调用JS函数SubmitBlodEntryForm(),传递表单ID和用于AJAX请求的网址。 The code of that JS function is here: 该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); 

}

The AJAX request is submitted to and received by the server (a Django view). AJAX请求被提交到服务器并由服务器接收(Django视图)。 If I do not manually add the csrf token as shown in the JS code above (variable sendContent) and just send formData, I get a 403 error, apparently because the server does not find the token. 如果我没有手动添加上面的JS代码中所示的csrf令牌(变量sendContent),而只是发送formData,则会收到403错误,这显然是因为服务器未找到令牌。 It should be part of the form, though... 不过,它应该是表格的一部分...

When I try binding the received data to the respective form, the validation fails: 当我尝试将接收到的数据绑定到相应的表单时,验证失败:

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

If I print what is in request.POST, I get the following in the Terminal: 如果我打印出request.POST中的内容,则会在终端机中得到以下内容:

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

Apparently, the FormData object is empty. 显然,FormData对象为空。 I also assume this because I get the two following errors for two required fields in my form (by using form.errors.as_data()): 我也假设这是因为我在表单中的两个必填字段(通过使用form.errors.as_data())得到了以下两个错误:

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

What is going wrong? 怎么了? Did I mess up the template such that FormData() does not produce useful data? 我是否弄乱了模板,使FormData()无法产生有用的数据? Am I incorrectly creating the AJAX request? 我是否错误地创建了AJAX请求? Or is the problem on the server side (although I am hardly doing anything there so far)? 还是服务器端的问题(尽管到目前为止我几乎没有做任何事情)?

Thank you, any help is greatly appreciated! 谢谢您的任何帮助,不胜感激!

You have 2 problems 你有两个问题

  • You have to use FormData.append to add data to a request that uses Formdata. 您必须使用FormData.append将数据添加到使用Formdata的请求中。
  • FormData objects use the multipart/form-data content type in request(which is set automatically and correctly) FormData对象在请求中使用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);
...

It might be better to not pass the form element to FormData like this: 最好不要这样将form元素传递给FormData:

new FormData(document.getElementById(form_ID))

I'm almost sure, it's only supported by firefox. 我几乎可以肯定,只有Firefox支持。 Other browsers do not auto-populate the object. 其他浏览器不会自动填充对象。

Also where you do: 另外,您在哪里:

var sendContent = sendCSRFtoken+"&"+formData;

Since 'sendCSRFtoken' is a string, it calls the toString() method on formData and concatenates the two, that's why you get '[object FormData]' on the django side. 由于“ sendCSRFtoken”是一个字符串,因此它在formData上调用toString()方法并将其连接起来,这就是为什么在django端获得“ [object FormData]”的原因。

One way to make this work add the form fields using: 进行此工作的一种方法是使用以下方法添加表单字段:

formData.append(name, value);

Do the same for the CRSF token and then call send like this: 对CRSF令牌执行相同的操作,然后按以下方式调用send:

httpRequest.send(formData);

XMLHttpRequest has multiple overloads for send so you can send an encoded string too if you prefer: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send() XMLHttpRequest具有多个发送重载,因此您也可以根据需要发送编码的字符串: https : //developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#send()

It will be really helpful when debugging to have the network tab open in chrome developer tools before the ajax call to verify what gets posted is correct before ruling out the client-side. 在调试之前,在ajax调用之前先在chrome开发人员工具中打开“网络”标签,在排除客户端之前先验证发布的内容是否正确,这将非常有帮助。

Thanks to all of you. 感谢大家。 I now found the problem, stupid copy&paste. 我现在发现了问题,愚蠢的复制和粘贴。 The JS function submitBlogEntryForm() creating the AJAX request was bad. 创建AJAX请求的JS函数SubmitBlogEntryForm()不好。 Setting the httpRequest header 设置httpRequest标头

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

caused contradicting encoding instructions. 导致矛盾的编码指令。 I just removed this line altogether and also refrained from specifying "enctype" in the form tag in my template and left all this to be set by FormData() automatically. 我只是完全删除了这一行,并且还避免在模板的form标记中指定“ enctype”,并将所有这些都由FormData()自动设置。 Now it works! 现在可以了!

Thanks again for your help! 再次感谢你的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM