2016-04-03 47 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()自動設置。現在它工作了!

再次感謝您的幫助!