跳至內容

回應模型 - 返回類型

您可以透過註釋**路徑操作函式**的**返回類型**來宣告回應所使用的類型。

您可以像在函式**參數**中輸入資料一樣使用**類型註釋**,您可以使用 Pydantic 模型、列表、字典、純量值,例如整數、布林值等等。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> List[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

FastAPI 將使用此返回類型來

  • **驗證**返回的資料。
    • 如果資料無效(例如,您缺少一個欄位),則表示*您的*應用程式程式碼已損壞,沒有返回應有的內容,它將返回伺服器錯誤,而不是返回不正確的資料。這樣,您和您的客戶端就可以確定他們將收到預期的資料和資料形狀。
  • 在 OpenAPI *路徑操作*中,為回應新增一個**JSON Schema**。
    • 這將由**自動文件**使用。
    • 它也將由自動客戶端程式碼產生工具使用。

但最重要的是

  • 它將**限制並過濾**輸出資料到返回類型中定義的內容。
    • 這對於**安全性**尤其重要,我們將在下面看到更多相關內容。

response_model 參數

在某些情況下,您需要或想要返回一些與類型宣告不完全相同的資料。

例如,您可能想要**返回一個字典**或資料庫物件,但**將其宣告為 Pydantic 模型**。這樣,Pydantic 模型將會對您返回的物件(例如字典或資料庫物件)進行所有資料文件、驗證等操作。

如果您新增了返回類型註釋,工具和編輯器會抱怨(正確的)錯誤,告訴您您的函式返回的類型(例如 dict)與您宣告的類型(例如 Pydantic 模型)不同。

在這些情況下,您可以使用*路徑操作裝飾器*參數 response_model 來代替返回類型。

您可以在任何*路徑操作*中使用 response_model 參數

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()
  • 等等。
from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
from typing import Any, List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=List[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]

注意事項

請注意,response_model 是「裝飾器」方法(getpost 等)的參數。而不是您的*路徑操作函式*的參數,就像所有參數和主體一樣。

response_model 接收與您為 Pydantic 模型欄位宣告的類型相同的類型,因此,它可以是 Pydantic 模型,但它也可以是例如 Pydantic 模型的 list,例如 List[Item]

FastAPI 將使用此 response_model 進行所有資料文件、驗證等操作,並將**轉換和過濾輸出資料**到其類型宣告。

提示

如果您的編輯器、mypy 等中有嚴格的類型檢查,您可以將函式返回類型宣告為 Any

這樣,您就可以告訴編輯器您故意返回任何內容。但 FastAPI 仍然會使用 response_model 進行資料文件、驗證、過濾等操作。

response_model 優先順序

如果您同時聲明了返回類型和 response_model,則 response_model 將優先,並由 FastAPI 使用。

這樣,即使您返回的類型與響應模型不同,您也可以為函數添加正確的類型註釋,以供編輯器和 mypy 等工具使用。而且您仍然可以使用 response_model 讓 FastAPI 進行數據驗證、文檔生成等。

您也可以使用 response_model=None 來停用為該 *路徑操作* 建立響應模型,如果您要為不是有效 Pydantic 欄位的東西添加類型註釋,您可能需要這樣做,您將在下面的章節中看到一個示例。

返回相同的輸入數據

這裡我們聲明一個 UserIn 模型,它將包含一個明文密碼

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

資訊

要使用 EmailStr,請先安裝 email-validator

確保您建立一個 虛擬環境,啟動它,然後安裝它,例如

$ pip install email-validator

或使用

$ pip install "pydantic[email]"

我們使用這個模型來聲明我們的輸入,並使用相同的模型來聲明我們的輸出

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

現在,每當瀏覽器使用密碼建立使用者時,API 都會在響應中返回相同的密碼。

在這種情況下,這可能不是問題,因為是同一個使用者發送密碼。

但是,如果我們將相同的模型用於另一個 *路徑操作*,我們可能會將使用者的密碼發送給每個客戶端。

危險

除非您了解所有注意事項並且知道自己在做什麼,否則切勿像這樣儲存使用者的明文密碼或在響應中發送它。

新增輸出模型

我們可以建立一個包含明文密碼的輸入模型和一個不包含明文密碼的輸出模型

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

這裡,即使我們的 *路徑操作函數* 返回包含密碼的相同輸入使用者

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

...我們將 response_model 聲明為我們的模型 UserOut,它不包含密碼

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

因此,**FastAPI** 將負責過濾掉所有未在輸出模型中聲明的數據(使用 Pydantic)。

response_model 或返回類型

在這種情況下,由於兩個模型不同,如果我們將函數返回類型註釋為 UserOut,編輯器和工具會抱怨我們返回了無效的類型,因為它們是不同的類別。

這就是為什麼在這個例子中我們必須在 response_model 參數中聲明它。

...但請繼續閱讀下面的內容,了解如何克服這個問題。

返回類型和數據過濾

讓我們繼續前面的例子。我們希望**使用一種類型來註釋函數**,但我們希望能夠從函數返回實際包含**更多數據**的內容。

我們希望 FastAPI 繼續使用響應模型**過濾**數據。這樣即使函數返回更多數據,響應也只會包含響應模型中聲明的欄位。

在前面的例子中,由於類別不同,我們必須使用 response_model 參數。但這也意味著我們沒有從檢查函數返回類型的編輯器和工具中獲得支援。

但在大多數需要這樣做的情況下,我們希望模型只是像在此範例中一樣**過濾/移除**一些數據。

在這些情況下,我們可以使用類別和繼承來利用函數**類型註釋**,以便在編輯器和工具中獲得更好的支援,並且仍然獲得 FastAPI **數據過濾**功能。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user

這樣一來,我們不僅獲得了工具支援,例如編輯器和 mypy,因為這段程式碼在型別方面是正確的,而且我們也獲得了 FastAPI 的資料過濾功能。

這是如何運作的呢?讓我們來看看。🤓

型別註釋和工具

首先,讓我們看看編輯器、mypy 和其他工具是如何看待這段程式碼的。

BaseUser 擁有基礎欄位。然後 UserIn 繼承自 BaseUser 並新增了 password 欄位,因此它將包含兩個模型中的所有欄位。

我們將函式的返回型別註釋為 BaseUser,但實際上我們返回的是一個 UserIn 的實例。

編輯器、mypy 和其他工具不會對此提出抱怨,因為在型別方面,UserInBaseUser 的子類別,這意味著當預期型別是任何 BaseUser 時,它是一個*有效的*型別。

FastAPI 資料過濾

現在,對於 FastAPI 來說,它會查看返回型別,並確保您返回的內容**僅**包含在型別中宣告的欄位。

FastAPI 在內部使用 Pydantic 進行了一些操作,以確保類別繼承的這些規則不會用於返回資料的過濾,否則您最終可能會返回比預期多得多的資料。

這樣,您可以兼得兩者的優點:具有**工具支援**的型別註釋和**資料過濾**。

在文件中查看

當您看到自動產生的文件時,您可以檢查輸入模型和輸出模型都將擁有自己的 JSON Schema。

並且這兩個模型都將用於互動式 API 文件。

其他返回型別註釋

在某些情況下,您可能會返回一些不是有效的 Pydantic 欄位的內容,並且您在函式中對其進行註釋,只是為了獲得工具(編輯器、mypy 等)提供的支援。

直接返回 Response

最常見的情況是如進階文件中稍後所述,直接返回 Response

from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return JSONResponse(content={"message": "Here's your interdimensional portal."})

FastAPI 會自動處理這個簡單的情況,因為返回型別註釋是 Response 類別(或其子類別)。

工具也會很滿意,因為 RedirectResponseJSONResponse 都是 Response 的子類別,所以型別註釋是正確的。

註釋 Response 子類別

您也可以在型別註釋中使用 Response 的子類別。

from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/teleport")
async def get_teleport() -> RedirectResponse:
    return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")

這也可以運作,因為 RedirectResponseResponse 的子類別,FastAPI 會自動處理這個簡單的情況。

無效的返回型別註釋

但是,當您返回一些不是有效 Pydantic 型別的任意物件(例如資料庫物件)並在函式中像這樣註釋它時,FastAPI 會嘗試從該型別註釋建立一個 Pydantic 回應模型,並且會失敗。

如果您在不同型別之間使用類似聯集 的東西,其中一個或多個不是有效的 Pydantic 型別,也會發生同樣的情況,例如,這會失敗 💥

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

...這會失敗,因為型別註釋不是 Pydantic 型別,並且不僅僅是一個 Response 類別或子類別,它是 Responsedict 之間的聯集(兩者中的任何一個)。

停用回應模型

繼續以上述例子,您可能不希望 FastAPI 執行預設的資料驗證、文件生成、篩選等功能。

但您可能仍希望保留函式中的返回型別註釋,以便獲得編輯器和型別檢查器(例如 mypy)等工具的支援。

在這種情況下,您可以透過設定 response_model=None 來停用回應模型的生成。

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

這將使 FastAPI 跳過回應模型的生成,這樣您就可以擁有任何所需的返回型別註釋,而不會影響您的 FastAPI 應用程式。🤓

回應模型編碼參數

您的回應模型可以有預設值,例如:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • description: Union[str, None] = None(或在 Python 3.10 中使用 str | None = None)的預設值為 None
  • tax: float = 10.5 的預設值為 10.5
  • tags: List[str] = [] 的預設值為空列表:[]

但如果它們實際上沒有被儲存,您可能希望從結果中省略它們。

例如,如果您在 NoSQL 資料庫中有包含許多可選屬性的模型,但您不希望發送充滿預設值的冗長 JSON 回應。

使用 response_model_exclude_unset 參數

您可以設定*路徑操作裝飾器*參數 response_model_exclude_unset=True

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]

這樣,這些預設值就不會包含在回應中,只會包含實際設定的值。

因此,如果您向 ID 為 foo 的項目的*路徑操作*發送請求,則回應(不包括預設值)將是

{
    "name": "Foo",
    "price": 50.2
}

資訊

在 Pydantic v1 中,該方法稱為 .dict(),在 Pydantic v2 中已棄用(但仍支援),並重新命名為 .model_dump()

此處的範例使用 .dict() 以與 Pydantic v1 相容,但如果您可以使用 Pydantic v2,則應改用 .model_dump()

資訊

FastAPI 使用 Pydantic 模型的 .dict() 與其exclude_unset 參數來實現此目的。

資訊

您也可以使用

  • response_model_exclude_defaults=True
  • response_model_exclude_none=True

Pydantic 文件中針對 exclude_defaultsexclude_none 的說明。

具有預設值欄位值的資料

但是,如果您的資料具有模型中具有預設值的欄位的值,例如 ID 為 bar 的項目

{
    "name": "Bar",
    "description": "The bartenders",
    "price": 62,
    "tax": 20.2
}

它們將包含在回應中。

與預設值相同的資料

如果資料的值與預設值相同,例如 ID 為 baz 的項目

{
    "name": "Baz",
    "description": None,
    "price": 50.2,
    "tax": 10.5,
    "tags": []
}

FastAPI 足夠聰明(實際上,是 Pydantic 足夠聰明)可以意識到,即使 descriptiontaxtags 的值與預設值相同,它們也是明確設定的(而不是取自預設值)。

因此,它們將包含在 JSON 回應中。

提示

請注意,預設值可以是任何值,而不僅僅是 None

它們可以是列表 ([])、10.5float 值等。

response_model_includeresponse_model_exclude

您也可以使用*路徑操作裝飾器*參數 response_model_includeresponse_model_exclude

它們接受一個包含 strset,其中包含要包含的屬性名稱(省略其餘部分)或要排除的屬性名稱(包含其餘部分)。

如果您只有一個 Pydantic 模型並且想要從輸出中移除一些數據,則可以使用此方法作為快速捷徑。

提示

但仍然建議使用上述的想法,使用多個類別,而不是這些參數。

這是因為即使您使用 response_model_includeresponse_model_exclude 省略一些屬性,應用程式 OpenAPI(和文件中)產生的 JSON Schema 仍然是完整模型的 Schema。

這也適用於類似運作的 response_model_by_alias

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]

提示

語法 {"name", "description"} 會建立一個包含這兩個值的 set(集合)。

它等同於 set(["name", "description"])

使用 list(列表)而非 set(集合)

如果您忘記使用 set 而改用 listtuple(元組),FastAPI 仍然會將其轉換為 set 並且正確運作。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]

重點回顧

使用*路徑操作裝飾器*的參數 response_model 來定義回應模型,尤其要確保過濾掉私人數據。

使用 response_model_exclude_unset 只返回明確設定的值。