Django: openpyxl сохраняет книгу как вложение - программирование
Подтвердить что ты не робот

Django: 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, но в файле есть только объект adres, а не содержимое файла:

<openpyxl.workbook.Workbook object at 0x00000000042806D8>

Может кто-нибудь помочь?

4b9b3361

Ответ 1

Попробуйте:

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

save_virtual_workbook был специально разработан для вашего случая использования. Здесь docstring:

"" Вернуть книгу в память, подходящую для ответа Django. ""

Ответ 2

Я обычно использую

ws = wb.add_sheet("Pi")

вместо

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

Кроме того, вы можете попробовать: (см. документация)

wb.save(stream)

а затем используйте поток в HttpResponse.

Ответ 3

По крайней мере, в некоторых версиях 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 для потоковой передачи из файловой системы, а не из памяти.