Part which is working fine :
I have made a <form> whose submit call makes an ajax request.Code for the same :
$.ajax({
type: 'POST',
url: '/uploaded_proto_file/',
data: formdata,
processData: false,
contentType: false,
success: function (data) {
console.log("in success")
console.log("data is --->"+data)
return;
},
error: function (data) {
console.log("in error")
return;
}
});
I am able to receive the call for the same on the function below. Now i need to send a file (which is in my document structure) that needs to auto downloaded in my browser. I execute this function based on this answer
def uploaded_proto_file(request):
with open(
'/Users/metal/Documents/test_pb2.py','rb') as text_file:
response = HttpResponse(FileWrapper(text_file.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=test_pb2.py'
return response
The above code wasn't working fine, so I debugged it and found this error on the filewrapper statement
Now I changed the solution a bit but the file sent back in response is not getting auto downloaded , it is getting printed in the console (as my success block in ajax function has console.log(data))
Changed solution :
with open(
'/Users/metal/Documents/test_pb2.py','rb') as text_file:
response = HttpResponse(text_file, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=test_pb2.py'
return response
As you can see above I removed FileWrapper and was atleast able to send the file back to ajax request. But the problem still persists as the file is not getting auto downloaded.
P.S. : I have also tried opening the file in different modes like 'r','rb'.
Any help would be appreciated !
You can't return a file to an ajax request and expect it to be downloaded. What you need is to separate into a few steps:
Your ajax request triggers the file creation process
Django puts that file somewhere where it can be downloaded and returns the URL to the file as ajax response
Your js response handler can now do two things:
Generate a button in the HTML for the user to click and download the file (using the URL from the response)
Create the button and auto-click it (call .click() on it) and then delete it again. A bit like in this example
Related
I'm a beginner.
What I used was flask and pymongo.
If you press the button, it's "Like". It should be +1, but there is a key error at the bottom.
My python route code:
#app.route('/api/like', methods=['POST'])
def like_movie():
title_receive = request.form['title_give']
movie = db.toytoy.find_one({'title': title_receive})
current_like = movie['like']
new_like = current_like + 1
db.toytoy.update_one({'title': title_receive}, {'$set': {'like': new_like}})
return jsonify({'msg': 'like!'})
This is how I POST from JS
function like_movie(title) {
$.ajax({
type: 'POST',
url: '/api/like',
data: {title_give: title},
success: function (response) {
console.log(response)
alert(response['msg']);
window.location.reload();
}
});
}
I get an exception as below:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'title_give'
What I want is if it's 'like_btn'. If you press the button, it becomes +1.
The base problem in what you did is not respecting Content-type. From front JS, you are making a POST with JSON object. Which makes the request to have a content type of application/json.
In backend code, you use request.form which expects the request to be in the form encoded types (like application/x-www-form-urlencoded, multipart/form-data) etc.
So, you need to read the JSON content in backend, instead of reading from a form which is not available. Like below:
ui_req = request.get_json()
title_receive = ui_req['title_give']
And then parse other structures accordingly.
Ok, I was really hoping that one of the various other questions on this topic would help me but I simply can't make this work! I'm relatively new to React and using API requests. I'm looking to upload an excel file from my React app and then process it in python using FastAPI as the interface.
I've followed the various tutorials / documentation approaches and I just get a 422 Unprocessable Entity Error!
In React, my event handlers look like this:
When file is selected, set the file in state:
onFileChange = (event) => {
this.setState({
uploadFile: event.target.files[0],
isFileSelected: true
});
};
When the "Upload" button is pressed, append to a FormData object and send via an axios request (Database is the axios object):
onUploadClick = async (event) => {
event.preventDefault()
var formData = new FormData();
formData.append(
"UploadFile",
this.state.uploadFile,
this.state.uploadFile.name
);
this.setState({isFileUploaded: true})
console.log(this.state.uploadFile)
const headers={'Content-Type': this.state.uploadFile.type}
await Database.post("/FileUpload",formData,headers);
};
And my FastAPI handler looks like this:
#app.post("/FileUpload")
async def FileUpload(file: UploadFile = File(...)):
# do some things...
Can someone please put me out my misery?
Your problem is due to the same reason as
How to send file to fastapi endpoint using postman
The name of the file variable in your fastapi endpoint has to match the name of the key to the file of your formdata. That is, your javascript should be like
formData.append(
"file",
this.state.uploadFile,
this.state.uploadFile.name
);
in order for your endpoint to be able to access the file parameter. Otherwise change the parameter's name (UploadFile in your case).
I have one button in my react code and when I click it I should be able to download a file. I am using Python for backend(Not any framework). For react part I think this link explains what should be done. On button click, I should do an API call and on its return, I can render this IFrame component. Also, one other answer recommends responseType: 'blob' in axios call. My question is what should the backend do if we want to send a file over.Let's assume it just creates a file and returns it. I am actually using one third-party product which has its own API interface but an example with requests library would do.
def function_called_From_endpoint():
with open(path) as f:
return {'data': f }
Is something like this right?
So, I made it work this way:
def function_called_From_endpoint():
with open(file_path) as f:
data = f.read()
return {"data": data }
and on the front-end:
axios({
url: url, //your url
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.txt'); //or any other extension
document.body.appendChild(link);
link.click();
});
As suggested by https://stackoverflow.com/a/53230807/5573241. It worked well.
I am downloading file from Hadoop to Django backend and storing the file using the code below:
import shutil
import requests
url = 'http://112.138.0.12:9870/webhdfs/v1/user/username/1.jpg?op=OPEN&user.name=username'
response = requests.get(url, stream=True)
with open('img.png', 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file)
del response
I don't need to store the file in backend local system since I want to send this file to Angular 5 frontend where user will save this file in their local system. I'm getting the following error
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position
0: invalid start byte.
Can someone suggest me what would be the right way to do download large files in a short time?
DJANGO:
views.py:
class DownloadFileView(GenericAPIView):
serializer_class = UserNameSerializer
def get(self, request):
key = request.META.get('HTTP_AUTHORIZATION').split()[1]
user_id = Token.objects.get(key=key).user_id
user_name = User.objects.get(id=user_id).username
response = download_files(user_name)
return Response(response)
def download_files(user_name):
response = requests.get('http://112.138.0.12:9870/webhdfs/v1/user/' + user_name + '/1.jpg?op=OPEN&user.name=username', stream=True)
return response.raw
ANGULAR:
DownloadFile(){
this.userService.DownloadFiles().subscribe((data : any) => {
const blob = new Blob([data], { type: 'application/octet-stream'});
fileUrl = this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob));
}
}
DownloadFiles() {
this.token = localStorage.getItem('userToken')
var reqHeader = new HttpHeaders({ 'Content-Type': 'application/octet-stream', 'Authorization': 'token ' + this.token });
console.log(reqHeader)
return this.http.get(this.rootURL + 'download/', { headers: reqHeader});
}
To begin with your unicode error, it's because:
HttpResponse.init(content='', content_type=None, status=200,
reason=None, charset=None)
Instantiates an HttpResponse
object with the given page content and content type.
content should be an iterator or a string. If it’s an iterator, it
should return strings, and those strings will be joined together to
form the content of the response. If it is not an iterator or a
string, it will be converted to a string when accessed.
I do believe django is having trouble converting the binary data in the file to string. A more common approach when dealing with file downloads is:
response = HttpResponse(content_type="application/jpeg")
response.write(binary_data)
This works because there is a call to make_bytes behind the scenes which handles the binary data correctly.
Having said that, this is not the most efficient way to go about it. Your web app makes a request to a remote server using requests, and then passes that onto the client. Why not get your angular code to fetch the data directly from the end point?
Can't do that because you want authentication you say? Ok, How about checking the authentiation and then sending an HttpResponseDirect like this:
return HttpResponseRedirect('http://112.138.0.12:9870/webhdfs/v1/user/' + user_name + '/1.jpg?op=OPEN&user.name=username')
In my application, I'm rendering a PDF file and pass it back as a response. For this purpose I'm using flask_weasyprint's render_pdf, which does exactly this:
def render_pdf(html, stylesheets=None, download_filename=None):
if not hasattr(html, 'write_pdf'):
html = HTML(html)
pdf = html.write_pdf(stylesheets=stylesheets)
response = current_app.response_class(pdf, mimetype='application/pdf')
if download_filename:
response.headers.add('Content-Disposition', 'attachment', filename=download_filename)
return response
I now need to render a template + returning the rendered pdf as a download. Something like
#app.route("/view")
def view() :
resp1 = render_pdf(HTML(string="<p>Render me!</p>"), download_filename = "test.pdf")
resp2 = render_template("test.html")
return resp1, resp2
Is there any way to achieve this? Any workaround?
I am not sure if this is solvable in the backend, you want to send two http responses following one request. Should that be possible? (I really don't know) Shouldn't the client make two responses? (javascript).
An option would be, javascript datablob returned in your render_template call.
Maybe something like this? (untested):
fileData = new Blob([pdf_data_here], { type: 'application/pdf' });
fileUrl = URL.createObjectURL(fileData);
window.location.assign(fileUrl);
Or maybe just use the window.location.assign() function to generate the second request.
Or put the data base64 encoded in a href attribute?