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