15 KiB
Загрузка файлов
Используя класс File, мы можем позволить клиентам загружать файлы.
/// info | "Дополнительная информация"
Чтобы получать загруженные файлы, сначала установите python-multipart.
Например: pip install python-multipart.
Это связано с тем, что загружаемые файлы передаются как данные формы.
///
Импорт File
Импортируйте File и UploadFile из модуля fastapi:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial001_an.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001.py!}
////
Определите параметры File
Создайте параметры File так же, как вы это делаете для Body или Form:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial001_an.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001.py!}
////
/// info | "Дополнительная информация"
File - это класс, который наследуется непосредственно от Form.
Но помните, что когда вы импортируете Query, Path, File и другие из fastapi, на самом деле это функции, которые возвращают специальные классы.
///
/// tip | "Подсказка"
Для объявления тела файла необходимо использовать File, поскольку в противном случае параметры будут интерпретироваться как параметры запроса или параметры тела (JSON).
///
Файлы будут загружены как данные формы.
Если вы объявите тип параметра у функции операции пути как bytes, то FastAPI прочитает файл за вас, и вы получите его содержимое в виде bytes.
Следует иметь в виду, что все содержимое будет храниться в памяти. Это хорошо подходит для небольших файлов.
Однако возможны случаи, когда использование UploadFile может оказаться полезным.
Загрузка файла с помощью UploadFile
Определите параметр файла с типом UploadFile:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial001_an.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001.py!}
////
Использование UploadFile имеет ряд преимуществ перед bytes:
- Использовать
File()в значении параметра по умолчанию не обязательно. - При этом используется "буферный" файл:
- Файл, хранящийся в памяти до максимального предела размера, после преодоления которого он будет храниться на диске.
- Это означает, что он будет хорошо работать с большими файлами, такими как изображения, видео, большие бинарные файлы и т.д., не потребляя при этом всю память.
- Из загруженного файла можно получить метаданные.
- Он реализует file-like
asyncинтерфейс. - Он предоставляет реальный объект Python
SpooledTemporaryFileкоторый вы можете передать непосредственно другим библиотекам, которые ожидают файл в качестве объекта.
UploadFile
UploadFile имеет следующие атрибуты:
filename: Строкаstrс исходным именем файла, который был загружен (например,myimage.jpg).content_type: Строкаstrс типом содержимого (MIME type / media type) (например,image/jpeg).file:SpooledTemporaryFile(a file-like объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим файл в качестве объекта.
UploadFile имеет следующие методы async. Все они вызывают соответствующие файловые методы (используя внутренний SpooledTemporaryFile).
write(data): Записать данныеdata(strилиbytes) в файл.read(size): Прочитать количествоsize(int) байт/символов из файла.seek(offset): Перейти к байту на позицииoffset(int) в файле.- Наример,
await myfile.seek(0)перейдет к началу файла. - Это особенно удобно, если вы один раз выполнили команду
await myfile.read(), а затем вам нужно прочитать содержимое файла еще раз.
- Наример,
close(): Закрыть файл.
Поскольку все эти методы являются async методами, вам следует использовать "await" вместе с ними.
Например, внутри async функции операции пути можно получить содержимое с помощью:
contents = await myfile.read()
Если вы находитесь внутри обычной def функции операции пути, можно получить прямой доступ к файлу UploadFile.file, например:
contents = myfile.file.read()
/// note | "Технические детали async"
При использовании методов async FastAPI запускает файловые методы в пуле потоков и ожидает их.
///
/// note | "Технические детали Starlette"
FastAPI наследует UploadFile непосредственно из Starlette, но добавляет некоторые детали для совместимости с Pydantic и другими частями FastAPI.
///
Про данные формы ("Form Data")
Способ, которым HTML-формы (<form></form>) отправляют данные на сервер, обычно использует "специальную" кодировку для этих данных, отличную от JSON.
FastAPI позаботится о том, чтобы считать эти данные из нужного места, а не из JSON.
/// note | "Технические детали"
Данные из форм обычно кодируются с использованием "media type" application/x-www-form-urlencoded когда он не включает файлы.
Но когда форма включает файлы, она кодируется как multipart/form-data. Если вы используете File, FastAPI будет знать, что ему нужно получить файлы из нужной части тела.
Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке MDN web docs for POST.
///
/// warning | "Внимание"
В операции функции операции пути можно объявить несколько параметров File и Form, но нельзя также объявлять поля Body, которые предполагается получить в виде JSON, поскольку тело запроса будет закодировано с помощью multipart/form-data, а не application/json.
Это не является ограничением FastAPI, это часть протокола HTTP.
///
Необязательная загрузка файлов
Вы можете сделать загрузку файла необязательной, используя стандартные аннотации типов и установив значение по умолчанию None:
//// tab | Python 3.10+
{!> ../../docs_src/request_files/tutorial001_02_an_py310.py!}
////
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial001_02_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial001_02_an.py!}
////
//// tab | Python 3.10+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001_02_py310.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001_02.py!}
////
UploadFile с дополнительными метаданными
Вы также можете использовать File() вместе с UploadFile, например, для установки дополнительных метаданных:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial001_03_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial001_03_an.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial001_03.py!}
////
Загрузка нескольких файлов
Можно одновременно загружать несколько файлов.
Они будут связаны с одним и тем же "полем формы", отправляемым с помощью данных формы.
Для этого необходимо объявить список bytes или UploadFile:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial002_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial002_an.py!}
////
//// tab | Python 3.9+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial002_py39.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial002.py!}
////
Вы получите, как и было объявлено, список list из bytes или UploadFile.
/// note | "Technical Details"
Можно также использовать from starlette.responses import HTMLResponse.
FastAPI предоставляет тот же starlette.responses, что и fastapi.responses, просто для удобства разработчика. Однако большинство доступных ответов поступает непосредственно из Starlette.
///
Загрузка нескольких файлов с дополнительными метаданными
Так же, как и раньше, вы можете использовать File() для задания дополнительных параметров, даже для UploadFile:
//// tab | Python 3.9+
{!> ../../docs_src/request_files/tutorial003_an_py39.py!}
////
//// tab | Python 3.6+
{!> ../../docs_src/request_files/tutorial003_an.py!}
////
//// tab | Python 3.9+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial003_py39.py!}
////
//// tab | Python 3.6+ без Annotated
/// tip | "Подсказка"
Предпочтительнее использовать версию с аннотацией, если это возможно.
///
{!> ../../docs_src/request_files/tutorial003.py!}
////
Резюме
Используйте File, bytes и UploadFile для работы с файлами, которые будут загружаться и передаваться в виде данных формы.