FastAPI开发文档教程-请求体-嵌套模型

admin 2026-01-10 10:51:56 编程 来源:ZONE.CI 全球网 0 阅读模式
  • List 字段
  • 具有子类型的 List 字段
    • 从 typing 导入 List
    • 声明具有子类型的 List
  • Set 类型
  • 嵌套模型
    • 定义子模型
    • 将子模型用作类型
  • 特殊的类型和校验
  • 带有一组子模型的属性
  • 深度嵌套模型
  • 纯列表请求体
  • 无处不在的编辑器支持
  • 任意 dict 构成的请求体
  • 总结

    使用 FastAPI,你可以定义、校验、记录文档并使用任意深度嵌套的模型(归功于Pydantic)。

    List 字段

    你可以将一个属性定义为拥有子元素的类型。例如 Python list

    Python 3.10+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel
    3. app = FastAPI()
    4. class Item(BaseModel):
    5. name: str
    6. description: str | None = None
    7. price: float
    8. tax: float | None = None
    9. tags: list = []
    10. @app.put("/items/{item_id}")
    11. async def update_item(item_id: int, item: Item):
    12. results = {"item_id": item_id, "item": item}
    13. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: list = []
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`

    这将使 tags 成为一个由元素组成的列表。不过它没有声明每个元素的类型。

    具有子类型的 List 字段

    但是 Python 有一种特定的方法来声明具有子类型的列表:

    从 typing 导入 List

    首先,从 Python 的标准库 typing 模块中导入 List

    1. from typing import List, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: List[str] = []
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`

    声明具有子类型的 List

    要声明具有子类型的类型,例如 listdicttuple

    • typing 模块导入它们
    • 使用方括号 [] 将子类型作为「类型参数」传入
    1. from typing import List
    2. my_list: List[str]`

    这完全是用于类型声明的标准 Python 语法。

    对具有子类型的模型属性也使用相同的标准语法。

    因此,在我们的示例中,我们可以将 tags 明确地指定为一个「字符串列表」:

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel
    3. app = FastAPI()
    4. class Item(BaseModel):
    5. name: str
    6. description: str | None = None
    7. price: float
    8. tax: float | None = None
    9. tags: list[str] = []
    10. @app.put("/items/{item_id}")
    11. async def update_item(item_id: int, item: Item):
    12. results = {"item_id": item_id, "item": item}
    13. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: list[str] = []
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`
    1. from typing import List, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: List[str] = []
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`

    Set 类型

    但是随后我们考虑了一下,意识到标签不应该重复,它们很大可能会是唯一的字符串。

    Python 具有一种特殊的数据类型来保存一组唯一的元素,即 set

    然后我们可以导入 Set 并将 tag 声明为一个由 str 组成的 set

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel
    3. app = FastAPI()
    4. class Item(BaseModel):
    5. name: str
    6. description: str | None = None
    7. price: float
    8. tax: float | None = None
    9. tags: set[str] = set()
    10. @app.put("/items/{item_id}")
    11. async def update_item(item_id: int, item: Item):
    12. results = {"item_id": item_id, "item": item}
    13. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: set[str] = set()
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`
    1. from typing import Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Item(BaseModel):
    6. name: str
    7. description: Union[str, None] = None
    8. price: float
    9. tax: Union[float, None] = None
    10. tags: Set[str] = set()
    11. @app.put("/items/{item_id}")
    12. async def update_item(item_id: int, item: Item):
    13. results = {"item_id": item_id, "item": item}
    14. return results`

    这样,即使你收到带有重复数据的请求,这些数据也会被转换为一组唯一项。

    而且,每当你输出该数据时,即使源数据有重复,它们也将作为一组唯一项输出。

    并且还会被相应地标注 / 记录文档。

    嵌套模型

    Pydantic 模型的每个属性都具有类型。

    但是这个类型本身可以是另一个 Pydantic 模型。

    因此,你可以声明拥有特定属性名称、类型和校验的深度嵌套的 JSON 对象。

    上述这些都可以任意的嵌套。

    定义子模型

    例如,我们可以定义一个 Image 模型:

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: str name: str
    6. class Item(BaseModel):
    7. name: str
    8. description: str | None = None
    9. price: float
    10. tax: float | None = None
    11. tags: set[str] = set()
    12. image: Image | None = None
    13. @app.put("/items/{item_id}")
    14. async def update_item(item_id: int, item: Item):
    15. results = {"item_id": item_id, "item": item}
    16. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: str name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: Union[str, None] = None
    10. price: float
    11. tax: Union[float, None] = None
    12. tags: set[str] = set()
    13. image: Union[Image, None] = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`
    1. from typing import Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: str name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: Union[str, None] = None
    10. price: float
    11. tax: Union[float, None] = None
    12. tags: Set[str] = set()
    13. image: Union[Image, None] = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`

    将子模型用作类型

    然后我们可以将其用作一个属性的类型:

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: str
    6. name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: str | None = None
    10. price: float
    11. tax: float | None = None
    12. tags: set[str] = set()
    13. image: Image | None = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: str
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: set[str] = set()
    14. image: Union[Image, None] = None
    15. @app.put("/items/{item_id}")
    16. async def update_item(item_id: int, item: Item):
    17. results = {"item_id": item_id, "item": item}
    18. return results`
    1. from typing import Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: str
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: Set[str] = set()
    14. image: Union[Image, None] = None
    15. @app.put("/items/{item_id}")
    16. async def update_item(item_id: int, item: Item):
    17. results = {"item_id": item_id, "item": item}
    18. return results`

    这意味着 FastAPI 将期望类似于以下内容的请求体:

    { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2, "tags": ["rock", "metal", "bar"], "image": { "url": "http://example.com/baz.jpg", "name": "The Foo live" } }

    再一次,仅仅进行这样的声明,你将通过 FastAPI 获得:

    • 对被嵌入的模型也适用的编辑器支持(自动补全等)
    • 数据转换
    • 数据校验
    • 自动生成文档

    特殊的类型和校验

    除了普通的单一值类型(如 strintfloat 等)外,你还可以使用从 str 继承的更复杂的单一值类型。

    要了解所有的可用选项,请查看关于 来自 Pydantic 的外部类型 的文档。你将在下一章节中看到一些示例。

    例如,在 Image 模型中我们有一个 url 字段,我们可以把它声明为 Pydantic 的 HttpUrl,而不是 str

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel, HttpUrl
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: HttpUrl name: str
    6. class Item(BaseModel):
    7. name: str
    8. description: str | None = None
    9. price: float
    10. tax: float | None = None
    11. tags: set[str] = set()
    12. image: Image | None = None
    13. @app.put("/items/{item_id}")
    14. async def update_item(item_id: int, item: Item):
    15. results = {"item_id": item_id, "item": item}
    16. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: Union[str, None] = None
    10. price: float
    11. tax: Union[float, None] = None
    12. tags: set[str] = set()
    13. image: Union[Image, None] = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`
    1. from typing import Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: Union[str, None] = None
    10. price: float
    11. tax: Union[float, None] = None
    12. tags: Set[str] = set()
    13. image: Union[Image, None] = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`

    该字符串将被检查是否为有效的 URL,并在 JSON Schema / OpenAPI 文档中进行记录。

    带有一组子模型的属性

    你还可以将 Pydantic 模型用作 listset 等的子类型:

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel, HttpUrl
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: HttpUrl
    6. name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: str | None = None
    10. price: float
    11. tax: float | None = None
    12. tags: set[str] = set()
    13. images: list[Image] | None = None
    14. @app.put("/items/{item_id}")
    15. async def update_item(item_id: int, item: Item):
    16. results = {"item_id": item_id, "item": item}
    17. return results`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: set[str] = set()
    14. images: Union[list[Image], None] = None
    15. @app.put("/items/{item_id}")
    16. async def update_item(item_id: int, item: Item):
    17. results = {"item_id": item_id, "item": item}
    18. return results`
    1. from typing import List, Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: Set[str] = set()
    14. images: Union[List[Image], None] = None
    15. @app.put("/items/{item_id}")
    16. async def update_item(item_id: int, item: Item):
    17. results = {"item_id": item_id, "item": item}
    18. return results`

    这将期望(转换,校验,记录文档等)下面这样的 JSON 请求体:

    { "name": "Foo", "description": "The pretender", "price": 42.0, "tax": 3.2, "tags": [ "rock", "metal", "bar" ], "images": [ { "url": "http://example.com/baz.jpg", "name": "The Foo live" }, { "url": "http://example.com/dave.jpg", "name": "The Baz" } ] }

    Info

    请注意 images 键现在具有一组 image 对象是如何发生的。

    深度嵌套模型

    你可以定义任意深度的嵌套模型:

    Python 3.10+Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel, HttpUrl
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: HttpUrl
    6. name: str
    7. class Item(BaseModel):
    8. name: str
    9. description: str | None = None
    10. price: float
    11. tax: float | None = None
    12. tags: set[str] = set()
    13. images: list[Image] | None = None
    14. class Offer(BaseModel):
    15. name: str
    16. description: str | None = None
    17. price: float
    18. items: list[Item]
    19. @app.post("/offers/")
    20. async def create_offer(offer: Offer):
    21. return offer`
    1. from typing import Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: set[str] = set()
    14. images: Union[list[Image], None] = None
    15. class Offer(BaseModel):
    16. name: str
    17. description: Union[str, None] = None
    18. price: float
    19. items: list[Item]
    20. @app.post("/offers/")
    21. async def create_offer(offer: Offer):
    22. return offer`
    1. from typing import List, Set, Union
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl
    7. name: str
    8. class Item(BaseModel):
    9. name: str
    10. description: Union[str, None] = None
    11. price: float
    12. tax: Union[float, None] = None
    13. tags: Set[str] = set()
    14. images: Union[List[Image], None] = None
    15. class Offer(BaseModel):
    16. name: str
    17. description: Union[str, None] = None
    18. price: float
    19. items: List[Item]
    20. @app.post("/offers/")
    21. async def create_offer(offer: Offer):
    22. return offer`

    Info

    请注意 Offer 拥有一组 Item 而反过来 Item 又是一个可选的 Image 列表是如何发生的。

    纯列表请求体

    如果你期望的 JSON 请求体的最外层是一个 JSON array(即 Python list),则可以在路径操作函数的参数中声明此类型,就像声明 Pydantic 模型一样:

    images: List[Image]

    例如:

    Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. from pydantic import BaseModel, HttpUrl
    3. app = FastAPI()
    4. class Image(BaseModel):
    5. url: HttpUrl
    6. name: str
    7. @app.post("/images/multiple/")
    8. async def create_multiple_images(images: list[Image]):
    9. return images`
    1. from typing import List
    2. from fastapi import FastAPI
    3. from pydantic import BaseModel, HttpUrl
    4. app = FastAPI()
    5. class Image(BaseModel):
    6. url: HttpUrl
    7. name: str
    8. @app.post("/images/multiple/")
    9. async def create_multiple_images(images: List[Image]):
    10. return images`

    无处不在的编辑器支持

    你可以随处获得编辑器支持。

    即使是列表中的元素:

    请求体 - 嵌套模型 - 图1

    如果你直接使用 dict 而不是 Pydantic 模型,那你将无法获得这种编辑器支持。

    但是你根本不必担心这两者,传入的字典会自动被转换,你的输出也会自动被转换为 JSON。

    任意 dict 构成的请求体

    你也可以将请求体声明为使用某类型的键和其他类型值的 dict

    无需事先知道有效的字段/属性(在使用 Pydantic 模型的场景)名称是什么。

    如果你想接收一些尚且未知的键,这将很有用。


    其他有用的场景是当你想要接收其他类型的键时,例如 int

    这也是我们在接下来将看到的。

    在下面的例子中,你将接受任意键为 int 类型并且值为 float 类型的 dict

    Python 3.9+Python 3.8+

    1. from fastapi import FastAPI
    2. app = FastAPI()
    3. @app.post("/index-weights/")
    4. async def create_index_weights(weights: dict[int, float]):
    5. return weights`
    1. from typing import Dict
    2. from fastapi import FastAPI
    3. app = FastAPI()
    4. @app.post("/index-weights/")
    5. async def create_index_weights(weights: Dict[int, float]):
    6. return weights`

    Tip

    请记住 JSON 仅支持将 str 作为键。

    但是 Pydantic 具有自动转换数据的功能。

    这意味着,即使你的 API 客户端只能将字符串作为键发送,只要这些字符串内容仅包含整数,Pydantic 就会对其进行转换并校验。

    然后你接收的名为 weightsdict 实际上将具有 int 类型的键和 float 类型的值。

    总结

    使用 FastAPI 你可以拥有 Pydantic 模型提供的极高灵活性,同时保持代码的简单、简短和优雅。

    而且还具有下列好处:

    • 编辑器支持(处处皆可自动补全!)
    • 数据转换(也被称为解析/序列化)
    • 数据校验
    • 模式文档
    • 自动生成的文档
    FastAPI开发文档教程-请求体-嵌套模型 编程

    FastAPI开发文档教程-请求体-嵌套模型

    List 字段具有子类型的 List 字段从 typing 导入 List声明具有子类型的 ListSet 类型嵌套模型定义子模型将子模型用作类型特殊的类型和校验带有一组子模型的属性深度嵌套模型纯列表
    FastAPI开发文档教程-路径参数和数值校验 编程

    FastAPI开发文档教程-路径参数和数值校验

    导入 Path声明元数据按需对参数排序按需对参数排序的技巧数值校验:大于等于数值校验:大于和小于等于数值校验:浮点数、大于和小于总结与使用 Query 为查询参数声明更多的校验和元数据的方式相同,你也
    FastAPI开发文档教程-请求体-多个参数 编程

    FastAPI开发文档教程-请求体-多个参数

    混合使用 Path、Query 和请求体参数多个请求体参数请求体中的单一值多个请求体参数和查询参数嵌入单个请求体参数总结既然我们已经知道了如何使用 Path 和 Query,下面让我们来了解一下请求体
    评论:0   参与:  0