fastapi教程翻译(十七): Request Files(请
客户端也可以上传文件到Fastapi,只需要指定File
格式即可。
解释
同Form
一样,想要接收上传的文件,需要先安装python-multipart
.安装命令:
pip install python-multipart
.
原因
这是因为上传的文件会被解析为 "form data".
一、导入 File
从fastapi
中导入 File
和 UploadFile
:
from fastapi import FastAPI, File, UploadFile
二、定义 File
参数
创建文件参数:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: bytes = File(...)
):
return {"file_size": len(file)}
解释
File
是直接继承自Form
类的子类.
申明File
请求体,你必须使用File
,因为如果不使用该类,将会被解释为查询参数或者是请求体参数。
文件类型会被上传为 "form"数据类型.
如果你申明路由视图函数参数类型为bytes
,FastAPI将会把文件转化为bytes
类型。
File
类型的内容是将内容保存在内存中的,比较适合小型文件。
下面是使用UploadFile
几种情况、
三、File
参数使用 UploadFile
类型
将File参数定义为UploadFile
类型:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: bytes = File(...)
):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(
file: UploadFile = File(...)
):
return {"filename": file.filename}
文件使用UploadFile
类型比bytes
的几种好处:
-
UploadFile
文件使用脱机文件:- 文件存储在内存中有一个最大限制,如果超过了这个界限,会保存在硬盘中
- 这意味着
UploadFile
将会对大文件,比如图片、视频、大二进制文件等,不会很快消耗掉所有内存 - 可以从上传的文件中得到元数据】
-
UploadFile
有 file-likeasync
交互. - 它公开了一个实际的Python [
SpooledTemporaryFile
](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile)对象,您可以将其直接传递给需要类似文件对象的其他库。
3.1. UploadFile
3.1.1 UploadFile
的属性:
-
filename
: 具有上载原始文件名的str
(例.myimage.jpg
). -
content_type
:content type
的字符串 (MIME type / media type) (例.image/jpeg
). -
file
:SpooledTemporaryFile
(a file-like object). 这是实际的Python文件,您可以将其直接传递给需要“类文件”对象的其他函数或库。
3.1.2 UploadFile
的 async
方法:
其实都是下面调用相应的文件方法(使用内部的'SpooledTemporaryFile`)。
-
write(data)
: 写data
(str
orbytes
) 到文件. -
read(size)
: 读size
(int
) bytes/characters 文件. -
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()
async
技术细节
当您使用async方法时,FastAPI在线程池中运行文件方法并等待它们。
Starlette
技术细节
FastAPI的UploadFile继承自Starlette的
UploadFile
,但是增加了一些必要的部分以使其与pydantic **和FastAPI的其他部分兼容。
四、"Form Data"?
HTML表单(<form> </ form>
)将数据发送到服务器的方式通常对该数据使用“特殊”编码,这与JSON不同。
FastAPI将确保从正确的位置而不是JSON读取数据。
技术细节
如果表单中的数据不包含文件,则通常使用“媒体类型”
application / x-www-form-urlencoded
编码。但是当表单包含文件时,它将被编码为
multipart / form-data
。 如果使用File
,** FastAPI **将知道它必须从主体的正确部位获取文件。
如果您想了解更多有关这些编码和表单字段的信息,请转到MDN web docs for POST
.
警告⚠️
您可以在路径操作中声明多个File和Form参数,但是您也不能声明希望以JSON形式接收的Body字段,因为请求的主体将使用multipart/form-data
,而不是application/json
。
这并不是FastAPI的限制,而是HTTP协议的一部分。
五、多个文件上传
如果需要一次性上传多个文件,需要定义为bytes
或UploadFile
的List
形式
from typing import List
from fastapi import FastAPI, File, UploadFile
from starlette.responses import HTMLResponse
app = FastAPI()
@app.post("/files/")
async def create_files(
files: List[bytes] = File(...)
):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles/")
async def create_upload_files(
files: List[UploadFile] = File(...)
):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)
你将会得到bytes
或UploadFile
的列表。
注意
请注意,自2019年4月14日起,Swagger UI不支持在同一表单字段中上传多个文件。 有关更多信息,请检查#4276 和#3641。
尽管如此,FastAPI已经使用标准OpenAPI与之兼容。
因此,只要Swagger UI支持多文件上传或任何其他支持OpenAPI的工具,它们都将与FastAPI兼容。