Работа с файлами встречается на многих сайтах, поэтому я решил написать эту статью с кратким, но информативным содержанием.

Примеры кода можно использовать, как основу, которую при необходимости можно без каких-либо сложностей расширять под вашу конкретную задачу

Не буду долго расписывать предисловие, приступим к разбору.

  1. Скачивание файла

Скачивание файла реализуется очень просто, фактически в одну строку:

from fastapi import FastAPI
from fastapi.responses import FileResponse

app = FastAPI()


@app.get("/file/download")
def download_file():
  return FileResponse(path='data.xlsx', filename='Статистика покупок.xlsx', media_type='multipart/form-data')

Мы импортируем FileResponse, и возвращаем его с тремя параметрами(filename и media_type необязательные)

Первый параметр path указывает на файл, который будет скачан пользователем, это может быть как строка, так и os.PathLike.

В данном случае я указал относительный путь, мой файл data.xlsx лежит рядом с исполняемым файлом.

Параметр filename определяет имя файла на выходе, а то есть то, с каким названием пользователь его скачает, достаточно удобная функциональность позволяющая хранить файл с удобным для нас названием, при этом пользователю отдавать его с красивым наименованием.

И последний параметр, который я использовал, это media_type, он указывает на MIME-тип, в данном случае multipart/form-data, указывающий, что мы ожидаем набор данных из HTML-формы.

Файл может быть абсолютно любой, я в качестве примера использовал файл Excel.

2. Как отправить файл на сервер?

Отправка файла ничем не сложнее скачивания.

Нам нужно докачать модуль python-multipart

$ pip install python-multipart

У нас есть 2 способа работы с принятым файлом:

С помощью File и UploadFile

from fastapi import FastAPI, UploadFile, File

app = FastAPI()


@app.post("/file/upload-bytes")
def upload_file_bytes(file_bytes: bytes = File()):
  return {'file_bytes': str(file_bytes)}


@app.post("/file/upload-file")
def upload_file(file: UploadFile):
  return file

В методе с File мы получаем на выходе только байт-строку, которую я преобразовал к строковому типу, для вывода в документации ответа.

Этот метод используют только в том случае, когда нам кроме содержимого файла ничего не нужно, мы прокидываем байты в Pandas(если у нас Excel-формат), например, и тогда начинаем с ним непосредственно работать.

Метод UploadFile несколько более интересный в плане параметров, он имеет их целый набор.

Хочешь взять имя отправленного файла? Есть метод file.filename.

Нужен сам файл, а не его байты? Метод file.file.

Нужны байты? Пожалуйста, file.file.read().

Также есть и другие, которые я решил не перечислять, так как я сделал краткий гайд, а не переписывание документации(ссылку страницу которой я оставил в конце статьи)

Ну а просто file возвращает нам словарь различных данных о файле

Вот такая получилась кратенькая статья для быстрого старта, за более подробной информацией предлагаю обратиться к документации.

Комментарии (5)


  1. rSedoy
    13.01.2023 09:03
    +3

    А про самое интересное и ничего не сказано: тема async не раскрыта (у нас же async фреймворк), про возможные проблемы, если я буду раздавать файл 1G, он будет весь в память загружен или частями, нет ничего про насколько это проигрывает или выигрывает, если сравнивать с раздачей файлов через тот же nginx.


    1. rSedoy
      13.01.2023 09:45
      +2

      И последний параметр, который я использовал, это media_type, он указывает на MIME-тип, в данном случае multipart/form-data, указывающий, что мы ожидаем набор данных из HTML-формы.

      ох, только сейчас заметил, у ответа media_type это про тип файла, в данном случае это application/vnd.openxmlformats-officedocument.spreadsheetml.sheet


  1. baldr
    13.01.2023 10:37
    +4

    Ну это же даже меньше чем в родной справке примеров!

    Сеньор программист выше очень правильно заметил про async, и размер файла, и про mime-type. Хватит уже бояться StreamingResponse - очень просто и удобно реализуется, разгружает память, процессор, сеть и прокси.

    Указывая правильный MIME-тип в ответе вы подсказываете браузеру и ОС чем можно сразу открыть файл.


  1. WondeRu
    13.01.2023 12:14
    +2

    Для высоконагруженных сервисов мы делали передачу через S3: когда скачиваем - просто передаем через API подписанный URL, который экспайрится через 5 минут. А когда закачка, то клиенту тоже даем подписанный URL для закачки https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html. Это все интересно, когда файлы большие, а когда маленькие, то да - проще пихать через API.


  1. Ximik87
    13.01.2023 14:18
    +2

    В чем смысл статьи? пересказ документации? или у FastApi нет документации? или описан очень пограничный кейс, с которым редко сталкиваешься?