Как создать файл Excel с использованием BytesIO и отправить его клиенту через FastAPI?

Как можно изменить код, чтобы он генерировал файл Excel и отправлял его клиенту через FastAPI, не сохраняя файл физически на сервере? Я использую библиотеку openpyxl для генерации файла Excel. Вот мой текущий код для генерации:

```python
def create_xl(append_data):
    one_list = 0
    wb = Workbook()
    with NamedTemporaryFile(delete=True) as tmp:
        tmp.close()
        wb2 = wb.active
        add_first_column(wb2)
        while one_list < len(append_data):
            for index in cells:
                number = 2
                for elem in append_data[one_list]:
                    wb2[f'{index}{number}'] = elem
                    number += 1
                one_list += 1
        wb.save(tmp.name)
    return tmp.name
```

И вот код, который отправляет этот файл клиенту через FastAPI:

```python
def historydatasnils(pnils = Form()):
    append_data_fio = history_pnils(snils)
    streams = create_xl(append_data_fio)
    return FileResponse(streams, 
                        filename=f'{pnils}.xlsx', 
                        media_type="application/octet-stream")
```

Понимаю, что, вероятно, мне нужно использовать StreamingResponse для отправки сгенерированного на лету файла Excel. Но у меня не получается сделать это таким образом. Пожалуйста, подскажите, как это можно реализовать?
  • 16 октября 2023 г. 6:30
Ответы на вопрос 2
Да, для отправки файла Excel напрямую клиенту через FastAPI, можно использовать StreamingResponse вместо FileResponse. Вместо создания временного файла на диске, вы можете использовать BytesIO для генерации файла Excel в памяти и передавать его содержимое напрямую в Response.

Вот пример, как можно изменить ваш код для достижения этой цели:

```python
from io import BytesIO
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from openpyxl import Workbook

app = FastAPI()

def create_xl(append_data):
    wb = Workbook()
    wb2 = wb.active
    add_first_column(wb2)

    for index in cells:
        number = 2
        for elem in append_data:
            wb2[f'{index}{number}'] = elem
            number += 1

    output = BytesIO()
    wb.save(output)
    output.seek(0)
    return output


@app.get("/download")
def download_excel():
    append_data_fio = history_pnils(snils)
    stream = create_xl(append_data_fio)

    return StreamingResponse(stream, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={
        "Content-Disposition": "attachment; filename=example.xlsx"
    })
```

Здесь мы создали функцию `create_xl`, которая генерирует файл Excel и сохраняет его содержимое в BytesIO объект в памяти. Затем в обработчике `/download` используем StreamingResponse для передачи содержимого файла клиенту без сохранения его на диск.

Обратите внимание, что `media_type` установлен на `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` для указания правильного типа контента файла Excel. Если требуется поддержка старых форматов Excel (например, .xls), замените его соответствующим типом.

Таким образом, клиент при обращении к `/download` будет получать файл Excel для загрузки.
В ответе укажите заголовок Content-Disposition с названием файла. Для этого используйте StreamingResponse и передавайте в него байты. Необходимо обратить внимание, что не нужно создавать временный файл, который не будет удален после отправки. Для большей ясности можно обратиться к примеру на StackOverflow.
Похожие вопросы