Skip to content

Instantly share code, notes, and snippets.

@piersstorey
Last active March 30, 2019 13:23
Show Gist options
  • Save piersstorey/b32583f0cc5cba0a38a11c2b123af687 to your computer and use it in GitHub Desktop.
Save piersstorey/b32583f0cc5cba0a38a11c2b123af687 to your computer and use it in GitHub Desktop.
Flask xlsx writer
from flask import Response
import StringIO, mimetypes
import xlsxwriter
from datetime import datetime
from werkzeug.datastructures import Headers
def xlsx_export():
try:
# Flask response
response = Response()
response.status_code = 200
# Create an in-memory output file for the new workbook.
output = StringIO.StringIO()
# Craete workbook
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet('hello')
# Write some test data.
worksheet.write(0, 0, 'Hello, world!')
# Close the workbook before streaming the data.
workbook.close()
# Rewind the buffer.
output.seek(0)
# Add output to response
response.data = output.read()
# Set filname and mimetype
file_name = 'export_{}_{}.xlsx'.format('this_awesome', datetime.now())
mimetype_tuple = mimetypes.guess_type(file_name)
# HTTP headers for forcing file download
response_headers = Headers({
'Pragma': "public", # required,
'Expires': '0',
'Cache-Control': 'must-revalidate, post-check=0, pre-check=0',
'Cache-Control': 'private', # required for certain browsers,
'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition': 'attachment; filename=\"%s\";' % file_name,
'Content-Transfer-Encoding': 'binary',
'Content-Length': len(response.data)
})
if not mimetype_tuple[1] is None:
response.update({
'Content-Encoding': mimetype_tuple[1]
})
# Add headers
response.headers = response_headers
#jquery.fileDownload.js requirements
response.set_cookie('fileDownload', 'true', path='/')
# Return the response
return response
except Exception as e:
print(e)
@LukasSliacky
Copy link

Thanks for your gist.
I had to change:
output = StringIO.StringIO()
to
output = BytesIO()
but now always works great.

@DylanRussell
Copy link

i don't think mimetype is needed here when we know what the content-type should be, and the file isn't encoded.

also the Cache-Control header is overwritten here (it's used as a key twice in the dictionary), also according to this post:
https://stackoverflow.com/questions/34663916/are-cache-control-pre-check-and-post-check-headers-still-supported-by-ie
pre-check / post-check headers don't need to be used

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment