跳至内容

响应模型 - 返回类型

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

您可以像对函数参数中的输入数据一样使用类型注释,您可以使用 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 架构
    • 这将被自动文档使用。
    • 它也将被自动客户端代码生成工具使用。

但最重要的是

  • 它将限制和过滤输出数据,使其符合返回类型中定义的内容。
    • 这对于安全尤其重要,我们将在下面看到更多内容。

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 等)提供的支持。

直接返回响应

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

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

禁用响应模型

继续上面的示例,您可能不想使用 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 足够聪明)可以意识到,即使 `description`、`tax` 和 `tags` 与默认值具有相同的值,它们也被明确设置(而不是从默认值中获取)。

因此,它们将被包含在 JSON 响应中。

提示

请注意,默认值可以是任何东西,而不仅仅是 `None`。

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

response_model_includeresponse_model_exclude

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

它们接受一个包含属性名称的 `str` 的 `set`,用于指定要包含的属性(省略其余属性)或要排除的属性(包含其余属性)。

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

提示

但仍然建议使用上面的想法,使用多个类,而不是这些参数。

这是因为即使您使用 `response_model_include` 或 `response_model_exclude` 省略一些属性,应用程序的 OpenAPI(以及文档)中生成的 JSON Schema 仍然是完整模型的 JSON 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` 而是使用 `list` 或 `tuple`,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` 仅返回显式设置的值。