跳到内容

响应模型 - 返回类型

您可以通过注解路径操作函数返回类型来声明响应所使用的类型。

您可以像在函数参数中为输入数据一样使用类型注解,可以使用 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),
    ]

FastAPI 将使用此返回类型来

  • 验证返回的数据。
    • 如果数据无效(例如,您缺少一个字段),这意味着您的应用程序代码已损坏,未返回应有的内容,并且会返回服务器错误而不是错误的数据。这样,您和您的客户就可以确信他们将收到预期的数据和数据形状。
  • 为响应添加JSON Schema,在 OpenAPI 的路径操作中。
    • 这将由自动文档使用。
    • 它也将被自动客户端代码生成工具使用。

但最重要的是

  • 它将限制和过滤输出数据,使其仅包含在返回类型中定义的内容。
    • 这对于安全性尤为重要,我们将在下面进一步讨论。

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},
    ]

注意

请注意,response_model 是“装饰器”方法(getpost 等)的参数,而不是您的路径操作函数的参数,这一点与所有参数和请求体一样。

response_model 接收与您为 Pydantic 模型字段声明的类型相同的值,因此,它可以是 Pydantic 模型,但也可以是 Pydantic 模型列表,例如 List[Item]

FastAPI 将使用此 response_model 来完成所有数据文档、验证等工作,并转换和过滤输出数据以匹配其类型声明。

提示

如果您在编辑器中启用了严格类型检查,例如 mypy,您可以将函数返回类型声明为 Any

这样您就可以告诉编辑器您有意返回任何内容。但是 FastAPI 仍然会使用 response_model 来进行数据文档、验证、过滤等工作。

response_model 优先级

如果您同时声明了返回类型和 response_model,则 response_model 将具有优先权并由 FastAPI 使用。

这样,您就可以为函数添加正确的类型注解,即使您返回的类型与响应模型不同,以便编辑器和 mypy 等工具使用。同时,您仍然可以获得 FastAPI 使用 response_model 进行数据验证、文档记录等功能。

您还可以使用 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 等)提供的支持。

直接返回响应

最常见的情况是直接返回响应,如高级文档后面所述

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 的子类

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 之间的联合(两者之一)。

禁用响应模型

继续上面的例子,您可能不希望 having the default data validation, documentation, filtering, etc. that is performed by 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]
  • 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]

并且这些默认值将不会包含在响应中,只有实际设置的值才会。

因此,如果您向该路径操作发送请求以获取 ID 为 foo 的项,响应(不包含默认值)将是

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

信息

您也可以使用

  • 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

它们可以是列表([])、float10.5)等。

response_model_includeresponse_model_exclude

您还可以使用路径操作装饰器参数 response_model_includeresponse_model_exclude

它们接受一个 set of str,其中包含要包含(省略其余)或排除(包含其余)的属性名称。

如果只有一个 Pydantic 模型并想从输出中删除一些数据,可以使用此方法作为快速快捷方式。

提示

但仍建议使用上述方法,即使用多个类,而不是这些参数。

这是因为在您的应用程序 OpenAPI(以及文档)中生成的 JSON Schema 仍然是完整模型的 Schema,即使您使用 response_model_includeresponse_model_exclude 来省略某些属性。

这也适用于 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 来仅返回显式设置的值。