Flask: force download pdf files to open in browser - python

I'm trying to download a PDF file using flask but I don't want the file to download as an attachment. I simply want it to appear in the user's browser as a separate webpage. I've tried passing the as_attachment=False option to the send_from_directory method but no luck.
Here is my function so far:
#app.route('/download_to_browser')
def download_to_browser(filename):
return send_from_directory(directory=some_directory,
filename=filename,
as_attachment=False)
The function works in the sense that the file is downloading to my computer but I'd much rather just display it in the browser (and let the user download the file if they want to).
I read here I need to change thecontent-disposition parameter but I'm not sure how that can be done efficiently (perhaps using a custom response?). Any help?
Note: I'm not using Flask-Uploads at the moment but I probably will down the line.

You can try to add the mimetype parameter to send_from_directory:
return send_from_directory(directory=some_directory,
filename=filename,
mimetype='application/pdf')
That works for me, at least with Firefox.
If you need more control over headers, you can use a custom response, but you will lose the advantages of send_file() (I think it does something clever to serve the file directly from the webserver.)
with open(filepath) as f:
file_content = f.read()
response = make_response(file_content, 200)
response.headers['Content-type'] = 'application/pdf'
response.headers['Content-disposition'] = ...
return response

Related

File corrupted when using send_file() from flask, data from pymongo gridfs

Well my English is not good, and the title may looks weird.
Anyway, I'm now using flask to build a website that can store files, and mongodb is the database.
The file upload, document insert functions have no problems, the weird thing is that the file sent from flask send_file() was truncated for no reasons. Here's my code
from flask import ..., send_file, ...
import pymongo
import gridfs
#...
#app.route("/record/download/<record_id>")
def api_softwares_record_download(record_id):
try:
#...
file = files_gridfs.find_one({"_id": record_id})
file_ext = filetype.guess_extension(file.read(2048))
filename = "{}-{}{}".format(
app["name"],
record["version"],
".{}".format(file_ext) if file_ext else "",
)
response = send_file(file, as_attachment=True, attachment_filename=filename)
return response
except ...
The original image file, for example, is 553KB. But the response body returns 549.61KB, and the image was broken. But if I just directly write the file to my disk
#...
with open('test.png', 'wb+') as file:
file.write(files_gridfs.find_one({"_id": record_id}).read())
The image file size is 553KB and the image is readable.
When I compare the two files with VS Code's text editor, I found that the correct file starts with �PNG, but the corrupted file starts with �ϟ8���>�L�y
search the corrupted file head in the correct file
And I tried to use Blob object and download it from the browser. No difference.
Is there any wrong with my code or I misused send_file()? Or should I use flask_pymongo?
And it's interesting that I have found what is wrong with my code.
This is how I solved it
...file.read(2048)
file.seek(0)
...
file.read(2048)
file.seek(0)
...
response = send_file(file, ...)
return response
And here's why:
For some reasons, I use filetype to detect the file's extension name and mime type, so I sent 2048B to filetype for detection.
file_ext = filetype.guess_extension(file.read(2048))
file_mime = filetype.guess_mime(file.read(2048)) #this line wasn't copied in my question. My fault.
And I have just learned from the pymongo API that python (or pymongo or gridfs, completely unknown to this before) reads file by using a cursor. When I try to find the cursor's position using file.seek(), it returns 4096. So when I call file.read() again in send_file(), the cursor reads from 4096B away to the file head. 549+4=553, and here's the problem.
Finally I set the cursor to position 0 after every read() operation, and it returns the correct file.
Hope this can help if you made the same mistake just like me.

Download generated excel file using xslxwriter on Python(Django)

I am working with Python using the Django framework, at this moment I am generating some reports in Excel, for that I use the xslxwriter library, the user tries to download the file from the platform, I do not get the download and instead it The answer is strange characters, I think that's the Excel file, anyway I don't know how to make that file download.
This snippet is the one that is supposed to download the file
workbook.close()
output.seek(0)
response = HttpResponse(output.read(), content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = "attachment; filename=test.xlsx"
output.close()
return response
This is the response I get from the frontend
Thank you very much in advance.

What response should I return when returning an excel document in Django REST framework

I use openpyxl create a workbook, and return a Response like this:
from openpyxl import Workbook
wb = Workbook()
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xlsx"'
return response
but frontend coder said he accept gibberish, you should return a bytearray like 0101010101,he can analysis and download
Now I return a response like this, he use node.js not vue download through a complex process
I am confused, what should I do?
To make a direct link to file try to use application/vnd.openxmlformats-officedocument.spreadsheetml.sheet content type.
I recomend you to use django-excel to work with excel. It's pretty easy to use and you could integrate different formats later.
There're alot of examples of downloading views. Check the methods starts with make_response_from_. I guess you could use some of them to build a file and return it as response.

How do I allow users to download a MIDI file with Flask without getting a 0 byte download?

I am writing an application that creates a midi file using the MIDIUtil library. When the user submits an HTML form, a midi file object is created with MIDIUtil. How do I allow the user to download this as a .mid file? I have tried the following code, but I end up downloading a file of 0 bytes.
return Response(myMIDIFile, mimetype='audio/midi')
I use a variant of the following code to allow my users to download images they generate. The below code should work for you. Please note that you will most likely need to specify the full server path to the file being downloaded.
from flask import send_file
download_filename = FULL_PATH_TO_YOUR_MIDI_FILE
return(send_file(filename_or_fp = download_filename,mimetype="audio/midi",as_attachment=True))
I ended up using this, and it worked.
new_file = open('test.mid', 'wb')
myMIDI.writeFile(new_file)
new_file.close()
new_file = open('test.mid', 'rb')
return send_file(new_file, mimetype='audio/midi')
Might want to just try using send_file
from flask import send_file
return send_file("yourmidifile.mid", as_attachement=True, mimetype="audio\midi")

Creating a URLretreive function using urllib2 in python

I want to have a function which can save a page from the web into a designated path using urllib2.
Problem with urllib is that it doesn't check for Error 404, but unfortunately urllib2 doesn't have such a function although it can check for http errors.
How can i make a function to save the file permanently to a path?
def save(url,path):
g=urllib2.urlopen(url)
*do something to save g to 'path'*
Just use .read() to get the contents and write it to a file path.
def save(url,path):
g = urllib2.urlopen(url)
with open(path, "w") as fH:
fH.write(g.read())

Categories

Resources