FastAPI教程 請求文件

2022-08-20 11:42 更新

File 用于定義客戶端的上傳文件。

說明

因為上傳文件以「表單數(shù)據(jù)」形式發(fā)送。

所以接收上傳文件,要預先安裝 python-multipart。

例如: pip install python-multipart。

導入 File

從 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}

定義 File 參數(shù)

創(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 更好用。

含 UploadFile 的 File 參數(shù)

定義 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)勢:

  • 使用 spooled 文件:存儲在內(nèi)存的文件超出最大上限時,F(xiàn)astAPI 會把文件存入磁盤;
  • 這種方式更適于處理圖像、視頻、二進制文件等大型文件,好處是不會占用所有內(nèi)存;
  • 可獲取上傳文件的元數(shù)據(jù);
  • 自帶 file-like async 接口;
  • 暴露的 Python SpooledTemporaryFile 對象,可直接傳遞給其他預期「file-like」對象的庫。

UploadFile

UploadFile 的屬性如下:

  • filename:上傳文件名字符串(str),例如, myimage.jpg;
  • content_type:內(nèi)容類型(MIME 類型 / 媒體類型)字符串(str),例如,image/jpeg;
  • file: SpooledTemporaryFile( file-like 對象)。其實就是 Python文件,可直接傳遞給其他預期 file-like 對象的函數(shù)或支持庫。

UploadFile 支持以下 async 方法,(使用內(nèi)部 SpooledTemporaryFile)可調(diào)用相應的文件方法。

  • write(data):把 data (str 或 bytes)寫入文件;
  • read(size):按指定數(shù)量的字節(jié)或字符(size (int))讀取文件內(nèi)容;
  • seek(offset):移動至文件 offset (int)字節(jié)處的位置;例如,await myfile.seek(0) 移動到文件開頭;執(zhí)行 await myfile.read() 后,需再次讀取已讀取內(nèi)容時,這種方法特別好用;
  • close():關閉文件。

因為上述方法都是 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 的其它部件兼容。

什么是 「表單數(shù)據(jù)」

與 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ù)。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號