首頁 >後端開發 >Python教學 >如何在 FastAPI POST 請求中接受 JSON 和文件上傳?

如何在 FastAPI POST 請求中接受 JSON 和文件上傳?

Mary-Kate Olsen
Mary-Kate Olsen原創
2024-12-19 10:35:12482瀏覽

How to accept both JSON and file uploads in a FastAPI POST request?

如何在 FastAPI POST 請求中新增檔案和 JSON 正文?

具體來說,我希望以下範例能夠工作:

from typing import List
from pydantic import BaseModel
from fastapi import FastAPI, UploadFile, File


app = FastAPI()


class DataConfiguration(BaseModel):
    textColumnNames: List[str]
    idColumn: str


@app.post("/data")
async def data(dataConfiguration: DataConfiguration,
               csvFile: UploadFile = File(...)):
    pass
    # read requested id and text columns from csvFile

如果這不是POST 請求的正確方法,請告訴我如何從上傳的CSV 檔案中選擇所需的列FastAPI。

根據FastAPI 文件:

您可以在路徑操作中聲明多個Form 參數,但不能同時聲明您希望以JSON 形式接收的Body 字段,因為請求的正文將使用application/x-www-form-urlencoded 而不是application/json進行編碼(當表單包含檔案時,它會被編碼為multipart/form-data)。

這不是 FastAPI 的限制,它是 HTTP 協定的一部分。

請注意,您需要先安裝 python-multipart — 如果您還沒有這樣做,因為上傳的檔案是作為「表單資料」發送的。例如:

pip install python-multipart

還應該注意的是,在下面的範例中,端點是使用普通 def 定義的,但您也可以使用 async def (根據您的需求)。請查看此答案,以了解有關 FastAPI 中 def 與 async def 的更多詳細資訊。

如果您正在尋找如何上傳檔案和字典/JSON 資料清單,請看看這個答案,以及這個答案和這個工作範例的答案(主要基於以下一些方法)。

方法1

如此處所述,可以使用檔案和表單同時定義檔案和表單欄位。下面是一個工作範例。如果您有大量參數並希望與端點分開定義它們,請查看此答案,以了解如何使用依賴項類別或 Pydantic 模型來聲明貼花表單欄位。

app.py

from fastapi import Form, File, UploadFile, Request, FastAPI
from typing import List
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.post("/submit")
def submit(
    name: str = Form(...),
    point: float = Form(...),
    is_accepted: bool = Form(...),
    files: List[UploadFile] = File(...),
):
    return {
        "JSON Payload": {
            "name": name,
            "point": point,
            "is_accepted": is_accepted,
        },
        "Filenames": [file.filename for file in files],
    }


@app.get("/", response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

您可以透過造訪下面的範本來測試上面的範例http://127.0.0.1:8000。如果您的模板不包含任何 Jinja 程式碼,您也可以傳回一個簡單的 HTMLResponse。

templates/index.html

<!DOCTYPE html>
<html>
   <body>
      <form method="post" action="http://127.0.0.1:8000/submit"  enctype="multipart/form-data">
         name : <input type="text" name="name" value="foo"><br>
         point : <input type="text" name="point" value=0.134><br>
         is_accepted : <input type="text" name="is_accepted" value=True><br>    
         <label for="files">Choose file(s) to upload</label>
         <input type="file">

您也可以測試此範例使用 /docs 處的互動式 OpenAPI/Swagger UI 自動文檔,例如http://127.0.0.1:8000/docs,或使用Python請求,如下圖:

test.py

from typing import List
from pydantic import BaseModel
from fastapi import FastAPI, UploadFile, File


app = FastAPI()


class DataConfiguration(BaseModel):
    textColumnNames: List[str]
    idColumn: str


@app.post("/data")
async def data(dataConfiguration: DataConfiguration,
               csvFile: UploadFile = File(...)):
    pass
    # read requested id and text columns from csvFile

方法 2

也可以使用 Pydantic 模型以及依賴項來通知 /submit 端點(在下面的範例中)參數化變數 base 依賴 Base 類別。請注意,此方法需要將基礎資料作為查詢(而不是主體)參數,然後對其進行驗證並轉換為 Pydantic 模型(在本例中,即基礎模型)。另外,請注意,永遠不應該透過查詢字串傳遞敏感數據,因為這會帶來嚴重的安全風險 - 請查看此答案以獲取有關該主題的更多詳細資訊。

返回Pydantic 模型實例時(在本例中,這是基礎)來自FastAPI 端點(例如下面的/submit 端點),它將使用jsonable_encoder 在幕後自動轉換為JSON 字串,如本節中詳細說明的回答。但是,如果您希望在端點內自行將模型轉換為JSON 字串,您可以使用Pydantic 的model_dump_json() (在Pydantic V2 中),例如,base.model_dump_json(),並直接返回自定義響應,正如之前鏈接的答案中所解釋的;因此,避免使用jsonable_encoder。否則,為了自己將模型轉換為字典,您可以使用Pydantic 的model_dump() (在Pydantic V2 中),例如,base.model_dump(),或簡單地dict(base) (請注意,從返回一個dict 物件一個端點,FastAPI 仍然會在幕後使用jsonable_encoder,如上面連結的答案中所述)。您也可以查看此答案以取得相關的 Pydantic 方法和文件。

除了使用 Pydantic 模型作為查詢參數之外,還可以直接在端點中定義查詢參數,如本答案所示,以及這個答案和這個答案。

除了基本查詢參數之外,以下/submit 端點還需要在請求中編碼為multipart/form-data 的檔案body.

app.py

pip install python-multipart

app.py

app.py

from fastapi import Form, File, UploadFile, Request, FastAPI
from typing import List
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")


@app.post("/submit")
def submit(
    name: str = Form(...),
    point: float = Form(...),
    is_accepted: bool = Form(...),
    files: List[UploadFile] = File(...),
):
    return {
        "JSON Payload": {
            "name": name,
            "point": point,
            "is_accepted": is_accepted,
        },
        "Filenames": [file.filename for file in files],
    }


@app.get("/", response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})
app.pyapp.pyapp.py同樣,您可以使用下面的模板進行測試,這次使用JavaScript 來修改form元素,以便將表單資料作為查詢參數傳遞到 URL 而不是表單資料。 templates/index.html

以上是如何在 FastAPI POST 請求中接受 JSON 和文件上傳?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn