Python Flask send_file StringIO blank files
Question:
I want to process a Pandas dataframe and send it to download as a CSV without a temp file. The best way to accomplish this I’ve seen is to use StringIO
. Using the code below, a file downloads with the proper name, however the file is completely blank, and no error is shown. Why doesn’t the file contain data?
@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,
download_name='a_file.txt',
mimetype='text/csv'
)
Answers:
Use BytesIO
to 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'Just 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,
download_name='a_file.txt',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name
was called attachment_filename
.
if someone use python 2.7 with Flask and got the error about the module StringIO by importing it. This post can help you to solve your problem.
If you are importing String IO module, you can just change the import syntax by using this : from io import StringIO instead from StringIO import StringIO.
You can Also use from io import BytesIO if you are using image or some others ressource.
Thank you
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,
download_name='test.csv',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name
was called attachment_filename
.
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 a
Response
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 with csv
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
I want to process a Pandas dataframe and send it to download as a CSV without a temp file. The best way to accomplish this I’ve seen is to use StringIO
. Using the code below, a file downloads with the proper name, however the file is completely blank, and no error is shown. Why doesn’t the file contain data?
@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,
download_name='a_file.txt',
mimetype='text/csv'
)
Use BytesIO
to 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'Just 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,
download_name='a_file.txt',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name
was called attachment_filename
.
if someone use python 2.7 with Flask and got the error about the module StringIO by importing it. This post can help you to solve your problem.
If you are importing String IO module, you can just change the import syntax by using this : from io import StringIO instead from StringIO import StringIO.
You can Also use from io import BytesIO if you are using image or some others ressource.
Thank you
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,
download_name='test.csv',
mimetype='text/csv'
)
Prior to Flask 2.0, download_name
was called attachment_filename
.
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 a
Response
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