File 用于定義客戶端的上傳文件。
說(shuō)明
因?yàn)樯蟼魑募浴副韱螖?shù)據(jù)」形式發(fā)送。
所以接收上傳文件,要預(yù)先安裝 python-multipart。
例如: pip install python-multipart。
從 fastapi 導(dǎo)入 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}
創(chuàng)建文件(File)參數(shù)的方式與 Body 和 Form 一樣:
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}
說(shuō)明
File 是直接繼承自 Form 的類。
注意,從 fastapi 導(dǎo)入的 Query、Path、File 等項(xiàng),實(shí)際上是返回特定類的函數(shù)。
提示
聲明文件體必須使用 File,否則,F(xiàn)astAPI 會(huì)把該參數(shù)當(dāng)作查詢參數(shù)或請(qǐng)求體(JSON)參數(shù)。
文件作為「表單數(shù)據(jù)」上傳。
如果把路徑操作函數(shù)參數(shù)的類型聲明為 bytes,F(xiàn)astAPI 將以 bytes 形式讀取和接收文件內(nèi)容。
這種方式把文件的所有內(nèi)容都存儲(chǔ)在內(nèi)存里,適用于小型文件。
不過(guò),很多情況下,UploadFile 更好用。
定義 File 參數(shù)時(shí)使用 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 相比有更多優(yōu)勢(shì):
UploadFile 的屬性如下:
UploadFile 支持以下 async 方法,(使用內(nèi)部 SpooledTemporaryFile)可調(diào)用相應(yīng)的文件方法。
因?yàn)樯鲜龇椒ǘ际?nbsp;async 方法,要搭配「await」使用。
例如,在 async 路徑操作函數(shù) 內(nèi),要用以下方式讀取文件內(nèi)容:
contents = await myfile.read()
在普通 def 路徑操作函數(shù) 內(nèi),則可以直接訪問(wèn) UploadFile.file,例如:
contents = myfile.file.read()
async 技術(shù)細(xì)節(jié)
使用 async 方法時(shí),F(xiàn)astAPI 在線程池中執(zhí)行文件方法,并 awiat 操作完成。
Starlette 技術(shù)細(xì)節(jié)
FastAPI 的 UploadFile 直接繼承自 Starlette 的 UploadFile,但添加了一些必要功能,使之與 Pydantic 及 FastAPI 的其它部件兼容。
與 JSON 不同,HTML 表單(<form></form>)向服務(wù)器發(fā)送數(shù)據(jù)通常使用「特殊」的編碼。
FastAPI 要確保從正確的位置讀取數(shù)據(jù),而不是讀取 JSON。
技術(shù)細(xì)節(jié)
不包含文件時(shí),表單數(shù)據(jù)一般用 application/x-www-form-urlencoded「媒體類型」編碼。
但表單包含文件時(shí),編碼為 multipart/form-data。使用了 File,F(xiàn)astAPI 就知道要從請(qǐng)求體的正確位置獲取文件。
編碼和表單字段詳見 MDN Web 文檔的 POST 小節(jié)。
警告
可在一個(gè)路徑操作中聲明多個(gè) File 和 Form 參數(shù),但不能同時(shí)聲明要接收 JSON 的 Body 字段。因?yàn)榇藭r(shí)請(qǐng)求體的編碼是 multipart/form-data,不是 application/json。
這不是 FastAPI 的問(wèn)題,而是 HTTP 協(xié)議的規(guī)定。
FastAPI 支持同時(shí)上傳多個(gè)文件。
可用同一個(gè)「表單字段」發(fā)送含多個(gè)文件的「表單數(shù)據(jù)」。
上傳多個(gè)文件時(shí),要聲明含 bytes 或 UploadFile 的列表(List):
from typing import List
from fastapi import FastAPI, File, UploadFile
from fastapi.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 的列表(list)。
筆記
注意,截至 2019 年 4 月 14 日,Swagger UI 不支持在同一個(gè)表單字段中上傳多個(gè)文件。詳見 #4276 和 #3641.
不過(guò),F(xiàn)astAPI 已通過(guò) OpenAPI 標(biāo)準(zhǔn)與之兼容。
因此,只要 Swagger UI 或任何其他支持 OpenAPI 的工具支持多文件上傳,都將與 FastAPI 兼容。
技術(shù)細(xì)節(jié)
也可以使用 from starlette.responses import HTMLResponse。
fastapi.responses 其實(shí)與 starlette.responses 相同,只是為了方便開發(fā)者調(diào)用。實(shí)際上,大多數(shù) FastAPI 的響應(yīng)都直接從 Starlette 調(diào)用。
本節(jié)介紹了如何用 File 把上傳文件聲明為(表單數(shù)據(jù)的)輸入?yún)?shù)。
更多建議: