Python Flask send_file StringIO blank files
Solution 1
The issue here is that in Python 3 you need to use StringIO
with csv.write
and send_file
requires BytesIO
, so you have to do both.
@app.route('/test_download')
def test_download():
row = ['hello', 'world']
proxy = io.StringIO()
writer = csv.writer(proxy)
writer.writerow(row)
# Creating the byteIO object from the StringIO Object
mem = io.BytesIO()
mem.write(proxy.getvalue().encode())
# seeking was necessary. Python 3.5.2, Flask 0.12.2
mem.seek(0)
proxy.close()
return send_file(
mem,
as_attachment=True,
attachment_filename='test.csv',
mimetype='text/csv'
)
Solution 2
I guess you should write bytes.
from io import BytesIO
from flask import Flask, send_file
app = Flask(__name__)
@app.route('/test_download', methods=['POST'])
def test_download():
# Use BytesIO instead of StringIO here.
buffer = BytesIO()
buffer.write(b'jJust some letters.')
# Or you can encode it to bytes.
# buffer.write('Just some letters.'.encode('utf-8'))
buffer.seek(0)
return send_file(buffer, as_attachment=True,
attachment_filename='a_file.txt',
mimetype='text/csv')
if __name__ == '__main__':
app.run(debug=True)
Solution 3
make_response
- To get Flask to download a csv file to the user, we pass a csv string to the
make_response
function, which returns aResponse
object. - Then we add a Header which tells the browser to accept the file as a download.
- The Mimetype also must be set to
text/csv
in order to get the web browser to save it in something other than an html document.
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/test_download', methods=['POST'])
def test_download():
with StringIO() as buffer:
# forming a StringIO object
buffer = StringIO()
buffer.write('Just some letters.')
# forming a Response object with Headers to return from flask
response = make_response(buffer.getvalue())
response.headers['Content-Disposition'] = 'attachment; filename=namaste.csv'
response.mimetype = 'text/csv'
# return the Response object
return response
P.S. It is preferred to use python's built-in
csv
library to deal withcsv
files
References
- https://matthewmoisen.com/blog/how-to-download-a-csv-file-in-flask/
- https://www.geeksforgeeks.org/stringio-module-in-python/
- https://docs.python.org/3/library/csv.html
Namaste 🙏
Daniel Hitchcock
Updated on July 09, 2022Comments
-
Daniel Hitchcock 4 months
I'm using python 3.5 and flask 0.10.1 and liking it, but having a bit of trouble with send_file. I ultimately want to process a pandas dataframe (from Form data, which is unused in this example but necessary in the future) and send it to download as a csv (without a temp file). The best way to accomplish this I've seen is to us StringIO.
Here is the code I'm attempting to use:
@app.route('/test_download', methods = ['POST']) def test_download(): buffer = StringIO() buffer.write('Just some letters.') buffer.seek(0) return send_file(buffer, as_attachment = True,\ attachment_filename = 'a_file.txt', mimetype = 'text/csv')
A file downloads with the proper name, however the file is completely blank.
Any ideas? Issues with encoding? Has this been answered elsewhere? Thanks!
-
Daniel Hitchcock over 6 yearsYes that works-- I just learned that flask on python 3 won't work with StringIO. Follow up question--do you know a way to convert a pandas dataframe into into a bytes csv for download?
-
lord63. j over 6 years@DanielHitchcock Hi, you should provide a Minimal, Complete, and Verifiable example so I can reproduce this problem(like this question, but with the pandas dataframe example), I don't quiet familiar with pandas so my current answer is no. You may ask another question if necessary.
-
Sanchit over 4 yearsThis should be the accepted answer since it is more generic in sense of exporting/download CSV file by using send_file() method.
-
Charles L. over 1 yearIn the encode I added
"utf-8-sig"
, or you might want"utf-8"
. Also see stackoverflow.com/questions/2223882/… -
Fips over 1 yearThe crucial part is "buffer.seek(0)" - I had a problem with an excel-file from pandas and it was solved with this line
-
Jacob Lester 4 months
mem.seek(0)
is needed otherwise get a "Failed - File incomple" error. Can confirm for Python 3.7.10 Flask 1.1.1