FastAPI教程 請(qǐng)求文件

2022-08-20 11:42 更新

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

說(shuō)明

因?yàn)樯蟼魑募浴副韱螖?shù)據(jù)」形式發(fā)送。

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

例如: pip install python-multipart。

導(dǎo)入 File

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

定義 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}

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

含 UploadFile 的 File 參數(shù)

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

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

UploadFile

UploadFile 的屬性如下:

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

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

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

因?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 的其它部件兼容。

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

與 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é)

本節(jié)介紹了如何用 File 把上傳文件聲明為(表單數(shù)據(jù)的)輸入?yún)?shù)。


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)