Django:openpyxl保存工作簿作为附件

时间:2013-04-15 13:11:08

标签: python django excel xlsx openpyxl

嗨,我有一个简单的问题。我没有在互联网上找到答案,也许有人可以帮助我。

所以我想将工作簿保存为附件,但我不知道如何看待示例:

    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

然后我尝试了:

response = HttpResponse(wb, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'
return response

它确实返回了xlsx文件,但是在文件中只有对象不是文件的内容:

<openpyxl.workbook.Workbook object at 0x00000000042806D8>

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:29)

试一试:

from openpyxl.writer.excel import save_virtual_workbook
...
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')

save_virtual_workbook专为您的用例而设计。这是一个文档字符串:

  

“”“返回一个适合Django响应的内存中工作簿。”“”

答案 1 :(得分:3)

我通常使用

ws = wb.add_sheet("Pi")

而不是

ws = wb.create_sheet()
ws.title = "Pi"

此外,你可以尝试:(见documentation

wb.save(stream)

然后在HttpResponse中使用流。

答案 2 :(得分:1)

至少在某些版本的django / python / openpyxl上,给定的解决方案不起作用。见https://bitbucket.org/openpyxl/openpyxl/issues/657/save_virtual_workbook-generates-junk-data

简单的工作解决方案:

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)

这里发生的事情是Django的HttpResponse是一个类似文件的对象。 Workbook.save()可以采用类似文件的对象。 (在内部,它使用zipfile,它采用文件名或类似文件的对象。)

如果您在内存中操作文件,这是最简单且可能最有效的解决方案。流式响应并不真正有意义,因为数据不是用生成器创建的。即使save_virtual_workbook有效,它写入的数据也会在它可读之前生成为块。

另一种选择是创建一个NamedTemporaryFile(来自tempfile或Django的包装器),将其传递给Workbook.save(),然后使用FileResponse从文件系统中传输它而不是记忆。