Django request.FILES gets name, filename but not file (blob) - javascript

I'm trying to send an audiofile via a POST request to the server (aws, ec2) and I'm using Django, but my request.FILES doesn't receive the blob file, but it DOES receive the key and the filename.
Everything worked fine when I ran this on localhost.
How can I get the file?
I'm enabling my website on chrome://flags/#unsafely-treat-insecure-origin-as-secure, so that I can access the microphone.
Using RecorderJs to generate a Blob object containing the recorded audio in WAV format.
Main.js
rec.exportWAV(function(blob){
...
var fd = new FormData();
fd.append('text', speech);
fd.append('audio', blob, 'test.wav');
$.ajax({
type: 'POST',
enctype: 'multipart/form-data',
url: url,
data: fd,
processData: false,
contentType: false,
success: function(response) {
console.log(response);
}
})
...
speech is String,
blob in console is Blob {size: 221228, type: "audio/wav"}, so it does exist.
Views.py:
#csrf_exempt
def get_blob(request):
thislist = []
for key in request.POST:
thislist.append(request.POST.get(key))
for key in request.FILES:
thislist.append(request.FILES.get(key).name)
json_stuff = json.dumps({"check": thislist})
return HttpResponse(json_stuff, content_type="application/json")
I've tried with and without enctype, doesn't make a difference.
I've tried setting contentType to multipart/form-data, doesn't make a difference.
The formdata seems to be sent correctly, because I can get the speech correctly (request.POST).
And I can get the key from request.FILES ('audio'), and get the filename ('test.wav').
If I try request.FILES['audio'].read(), it says MultiValueDictError.
If I try request.FILES.get('audio').read() it says AttributeError, 'NoneType' object has no attribute 'read'.
When I print request.POST I do get the dictionary with 'text': whatever text I've spoken.
When I print request.FILES I get an empty dictionary even though I can get the key and filename through
for key in request.FILES: and request.FILES['audio'].filename.
Does anyone know what's going on and/or can help me with the problem?

You may use read() method for it:
#csrf_exempt ## it doesn't work for post requests in later Django versions, so you need to disable it in another way or add a token to all post requests
def get_blob(request):
thislist = []
for key in request.POST:
thislist.append(request.POST.get(key))
for key in request.FILES:
thislist.append(request.FILES.get(key).name)
# I am not sure that "name" exists in the request — you may use any filename, although the following works with multipart requests.
with open(request.FILES["name"],"wb+") as f:
f.write(request.FILES['file'].read())
json_stuff = json.dumps({"check": thislist})
return HttpResponse(json_stuff, content_type="application/json")
By the way,
#csrf_exempt — doesn't work for post requests in later Django versions, as a token is checked before your view is even called. So, you may need to disable CSRF middleware or just add a correct 'X-CSRFToken' token to all requests.

Related

$.ajax post request not sending data parameters to server

I am running into problem requesting data from an API. The documentation states that I must make a post request. My goal is to make the request with jQuery, then style the resulting data.
Since I'm using a Cross-Domain-Request, I know that I have to use jsonp. The issue is that I get parseerror when I run this code because the server is returning an XML error. (The server defaults to an xml response if no format is specified)
$.ajax({
type: 'POST',
url: url,
data: {format: 'json'},
dataType: 'jsonp',
success: function(data) {
console.log("Success.");
},
error: function(data, error, err) {
console.log(data.status);
console.log(error);
console.log(err);
}
});
Inside the inspector I see:
Uncaught SyntaxError: Unexpected token <
menu?&callback=jQuery2240569993828256961_1469752734662&format=json&_=1469752734663:1
This is the XML response...
<?xml version="1.0" encoding="UTF-8"?><response> <response_header> <response_code>ERROR</response_code>
</response_header>
<response_details> <error_details>The post parameters contain an invalid or disabled API ID</error_details>
</response_details>
</response>
Because it returns XML, I can determine that the server is not even recognizing my parameter {format: 'json'}, because here is the same request in Python:
from urllib.parse import urlencode
from urllib.request import Request, urlopen
url = url # Set destination URL here
post_fields = {'format':'json'} # Set POST fields here
request = Request(url, urlencode(post_fields).encode())
json = urlopen(request).read().decode()
print(json)
And the resulting JSON response:
{"response_header":{"response_code":"ERROR"},"response_details":{"error_details":"The post parameters contain an invalid or disabled API ID"}}
As you can see, it responds with JSON demonstrating that the server read the post request.
For some reason, the AJAX request is not sending the parameters through which means I can't even get back the actual data I need by including the api key + api id.
Can anyone tell me what is going on here?
Thank you.

How to capture file downloaded as a result of cross domain post request?

I can not use Ajax because I do not have access to the third party server
File download starts automatically after submitting the form
I want to import this file (it's a CSV) into an array, but for that I need to somehow capture it
All examples that I researched are showing capture of a response to an AJAX call, which I can not use due to CORS.
Current code includes a post form, and a submit function.
This does not work due to CORS constraints:
$('#f1')
.ajaxForm({
url : $('#f1').attr('action'),
type: 'post',
dataType : 'document',
crossDomain: true,
success : function (response) {
alert("The server says: " + response);
}
})
This of course works but file is downloaded to the filesystem:
$('#f1').submit()
I need to somehow extract the attachment from the post reponse and load it into a variable.

Multipart or base64 for AJAX file uploads?

I'm writing a single page application with EmberJS and need to upload a few files.
I wrote a special view, that wraps the file input field and extracts the first file selected. This lets me bind the File-Object to a model-attribute.
Now I have to choose.
I can write a special file transform, that serialises the File-Object to base64 and simply PUT/POST this.
Or I can intercept the RESTAdapter methods createRecord and updateRecord to check every model for File-Objects and switch the PUT/POST requests to multipart/form-data and send it with the help of FormData
Does one of these directions pose significant problems?
I've had to evaluate the same concern for a Restful API I'm developing. In my opinion, the most ideal method would be to just use the RESTAdapter with base64 encoded data.
That being said, I had to use the multipart/form-data method in my case, because the data transfer is 30% higher when you base64 encode the file data. Since my API would be have to accept large (100MB+) files, I opted to have the POST method of the API to receive multipart form data, with the file and json data being one of the POST variables.
So, unless you need to upload large files like in my case, I'd recommend always sticking to the REST methods.
Just ran into this myself, and ended up using a simple jQuery AJAX call using the FormData object. My multi-select implementation (where one can drop multiple files at once) looks like this:
filesDidChange: function() {
// Get FileList
var $input = this.$('input'),
fileList = $input.get(0).files;
// Iterate files
for (var i = 0; i < fileList.length; i++) {
var file = fileList[i],
formData = new FormData();
// Append information to FormData instance
formData.append('attachment[title]', file.name);
formData.append('attachment[file]', file);
formData.append('attachment[post_id]', this.get('post.id'));
// Send upload request
Ember.$.ajax({
method: 'POST',
url: '/attachments',
cache: false,
contentType: false,
processData: false,
data: formData,
success: makeSuccessHandler(this),
error: makeErrorHandler(this)
});
}
// Notify
this.container.lookup('util:notification').notify('Uploading file, please wait...');
// Clear FileList
$input.val(null);
},

multipart/formdata is not sending file data with jQuery.ajax

I have an endpoint from our Django backend guys with documentation that reads:
POST to /api/1/photo-uploads/ with enctype="multipart/form-data" with files in field called "files[]".
I've been attempting to send uploaded files with formData using jquery's AJAX method. I continue to get an error indicating that the file was not sent. When I view the payload I see.
undefined
------WebKitFormBoundary9AzM2HQPcyWLAgyR
Content-Disposition: form-data; name="file"; filename="auzLyrW.jpg"
Content-Type: image/jpeg
Which doesn't necessarily mean that it hasn't sent but there certainly isn't a location being posted. And I don't have any kind of verification that the file is uploaded.
var formData = new FormData();
formData.append('file', $('#file-upload').get(0).files[0]);
$.ajax({
url: '/api/1/photo-uploads/',
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
});
When I console.log formData it simply show's the prototype methods like .append. So I'm unable to verify if the file's data is being sent beyond checking the payload. I can log $('#file-upload').get(0).files[0] but I only see details from the file itself. Because I'm testing it locally an upload location should be something like localhost:8000/.
The backend guys are under the impression that it's something I'm doing. When I do a simple form post it works fine. I've tried a number of plugins and basic methods and all have produced the 400 {"message": "No photos supplied.", "success": false}
Any ideas would be appreciated.
The documentation asked that it be called files[]. What was being sent was file.
formData.append('files[]', $('#file-upload').get(0).files[0]);

AJAX Post to store JSON with Python and javascript

I have been having problems with getting AJAX to post JSON correctly. The application is intended to be hosted on Google App Engine. But what I have does not post data.
Python
mainPage = """
<html>
html is included in my python file.
</html>
"""
class JSONInterface(webapp2.RequestHandler):
def post(self):
name =self.request.get('name')
nickname =self.request.get('nickname')
callback = self.request.get('callback')
if len(name) > 0 and len(nickname) >0:
newmsg = Entry(name=name, nickname=nickname)
newmsg.put()
if len(name)>0:
self.response.out.write(getJSONMessages(callback))
else:
self.response.out.write("something didnt work")
def get(self):
callback = self.request.get('callback')
self.response.out.write(getJSONMessages(callback))
This handler is meant to handle the Ajax calls from the web app. I am unsure if I need javascript to be associated with my main page in order to do so, as I haven't found information on it yet with my searches.
Javascript
$(document).ready( function() {
$("#post").bind('click', function(event){
var name = $("#name").val();
var nickname = $("#nickname").val();
postData = {name: name, nickname: nickname, callback: "newMessage"};
$.ajax({
type: "POST",
url: "http://localhost:27080/json",
data: postData,
dataType: "json",
done: function() {
// Clear out the posted message...
$("#nickname").val('');
},
fail: function(e) {
confirm("Error", e.message);
}
});
// prevent default posting of form (since we're making an Ajax call)...
event.preventDefault();
});
The Javascript for the post
Can someone advise me on how I could resolve the problem I am having. Thanks for the time and help.
Did you ask the same question yesterday and then delete it? I swear I just answered the same question.
You're not sending your data as a JSON string. If you want to send as JSON, you need to encode data as a JSON string, or else you're just sending it as a query string.
data: JSON.stringify(postdata),
HOWERVER, your request handler is actually processing the request properly as query string instead of JSON, so you probably don't want to do that.
For starters, the ajax call is pretty close. The full path
"http:://localhost:27080/json"
is not necessary, the relative path will work, but that is not the problem.
Your callback, as it stands, will work as 'success':
success: function(response) {
alert(response);
// Clear out the posted message...
$("#nickname").val('');
}
However, this callback is being phased out in favor of other methods. 'Done' should be chained like so:
$.ajax({
type: "POST",
url: "/json",
data: postData,
dataType: "json"
}).done(function(data){
console.log(data);
});
Also, there might be problems on the server. If you use some logging, you will see that the data is indeed being sent to the server.
import json ## we'll get to this below
import logging
class JSONInterface(webapp2.RequestHandler):
def post(self):
name = self.request.get('name')
logging.info(name) ## will print the value of 'name'
Unless your python function getJSONMessages(callback) is returning a json object, your callback will not be called, even after you add the response parameter.
In your python code:
import json
import logging
class JSONInterface(webapp2.RequestHandler):
def post(self):
callback = self.request.get('callback')
logging.info(callback) # will print correctly
self.response.out.write(json.dumps(callback))
Using the json.dumps method encodes the passing object to json, which is what your ajax object is looking for.

Categories