Django: openpyxl saving workbook as attachment
Question:
Hi I have a quick question. I didn’t find answer in internet maybe someone of you can help me.
So i want to save workbook as attachment but I don’t know how lets see an example :
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
wb = Workbook(encoding='utf-8')
dest_filename = 'file.xlsx'
ws = wb.worksheets[0]
ws.title = "range names"
for col_idx in xrange(1, 40):
col = get_column_letter(col_idx)
for row in xrange(1, 600):
ws.cell('%s%s'%(col, row)).value = '%s%s' % (col, row)
ws = wb.create_sheet()
ws.title = 'Pi'
ws.cell('F5').value = 3.14
Then I tried :
response = HttpResponse(wb, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'
return response
It’s returning xlsx file indeed but in file there is only object adres not the content of file:
<openpyxl.workbook.Workbook object at 0x00000000042806D8>
Can someone help ?
Answers:
I usually use
ws = wb.add_sheet("Pi")
instead of
ws = wb.create_sheet()
ws.title = "Pi"
Moreover, you can try to do: (see documentation)
wb.save(stream)
and then use stream in HttpResponse.
Give it a try:
from openpyxl.writer.excel import save_virtual_workbook
...
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')
save_virtual_workbook
was specially designed for your use case. Here’s a docstring:
“””Return an in-memory workbook, suitable for a Django response.”””
On at least some versions of django/python/openpyxl, the given solution does not work. See https://bitbucket.org/openpyxl/openpyxl/issues/657/save_virtual_workbook-generates-junk-data
Simple working solution:
wb = Workbook(write_only=True, encoding='utf-8')
ws = wb.create_sheet()
for row in data:
ws.append([str(cell) for cell in row])
response = HttpResponse(content_type='application/vnd.ms-excel')
wb.save(response)
What’s happening here is that Django’s HttpResponse is a file-like object. Workbook.save()
can take a file-like object. (Internally, it uses zipfile, which takes either a filename or a file-like object.)
If you’re manipulating the file in memory, this is the simplest and probably most efficient solution. A streaming response doesn’t really make sense since the data is not being created with a generator. Even if save_virtual_workbook works, the data it writes is generated as a block before it’s readable.
The other option would be to create a NamedTemporaryFile (from tempfile or Django’s wrapper), pass that into Workbook.save()
, then use FileResponse to stream that from the filesystem instead of from memory.
You can try also the following code lines.
You can also set your file name as you want.
wb = Workbook()
..............
..............
response = HttpResponse(save_virtual_workbook(wb),content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename='+str(yourFileName)+'_report'+'.xlsx'
return response
Hi I have a quick question. I didn’t find answer in internet maybe someone of you can help me.
So i want to save workbook as attachment but I don’t know how lets see an example :
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
wb = Workbook(encoding='utf-8')
dest_filename = 'file.xlsx'
ws = wb.worksheets[0]
ws.title = "range names"
for col_idx in xrange(1, 40):
col = get_column_letter(col_idx)
for row in xrange(1, 600):
ws.cell('%s%s'%(col, row)).value = '%s%s' % (col, row)
ws = wb.create_sheet()
ws.title = 'Pi'
ws.cell('F5').value = 3.14
Then I tried :
response = HttpResponse(wb, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'
return response
It’s returning xlsx file indeed but in file there is only object adres not the content of file:
<openpyxl.workbook.Workbook object at 0x00000000042806D8>
Can someone help ?
I usually use
ws = wb.add_sheet("Pi")
instead of
ws = wb.create_sheet()
ws.title = "Pi"
Moreover, you can try to do: (see documentation)
wb.save(stream)
and then use stream in HttpResponse.
Give it a try:
from openpyxl.writer.excel import save_virtual_workbook
...
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')
save_virtual_workbook
was specially designed for your use case. Here’s a docstring:
“””Return an in-memory workbook, suitable for a Django response.”””
On at least some versions of django/python/openpyxl, the given solution does not work. See https://bitbucket.org/openpyxl/openpyxl/issues/657/save_virtual_workbook-generates-junk-data
Simple working solution:
wb = Workbook(write_only=True, encoding='utf-8')
ws = wb.create_sheet()
for row in data:
ws.append([str(cell) for cell in row])
response = HttpResponse(content_type='application/vnd.ms-excel')
wb.save(response)
What’s happening here is that Django’s HttpResponse is a file-like object. Workbook.save()
can take a file-like object. (Internally, it uses zipfile, which takes either a filename or a file-like object.)
If you’re manipulating the file in memory, this is the simplest and probably most efficient solution. A streaming response doesn’t really make sense since the data is not being created with a generator. Even if save_virtual_workbook works, the data it writes is generated as a block before it’s readable.
The other option would be to create a NamedTemporaryFile (from tempfile or Django’s wrapper), pass that into Workbook.save()
, then use FileResponse to stream that from the filesystem instead of from memory.
You can try also the following code lines.
You can also set your file name as you want.
wb = Workbook()
..............
..............
response = HttpResponse(save_virtual_workbook(wb),content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename='+str(yourFileName)+'_report'+'.xlsx'
return response