是否为输入和输出分别创建 OpenAPI 架构¶
当使用 **Pydantic v2** 时,生成的 OpenAPI 比以前更精确,也更 **正确**。 😎
事实上,在某些情况下,它甚至会在 OpenAPI 中为同一个 Pydantic 模型创建 **两个 JSON 架构**,分别用于输入和输出,具体取决于它们是否有 **默认值**。
让我们看看它是如何工作的,以及如何在需要时进行更改。
用于输入和输出的 Pydantic 模型¶
假设您有一个带有默认值的 Pydantic 模型,例如:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
# Code below omitted 👇
👀 查看完整文件预览
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
# Code below omitted 👇
👀 查看完整文件预览
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
# Code below omitted 👇
👀 查看完整文件预览
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> List[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
输入模型¶
如果您像这样使用此模型作为输入:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
# Code below omitted 👇
👀 查看完整文件预览
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
# Code below omitted 👇
👀 查看完整文件预览
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
# Code below omitted 👇
👀 查看完整文件预览
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> List[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
...那么 description
字段 **将不是必需的**。因为它具有 None
的默认值。
文档中的输入模型¶
您可以在文档中确认 description
字段没有 **红色星号**,它没有被标记为必需的

输出模型¶
但是,如果您像这样使用同一个模型作为输出:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> List[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
...那么因为 description
具有默认值,如果您 **不返回任何内容** 到该字段,它仍然会保留该 **默认值**。
用于输出响应数据的模型¶
如果您与文档交互并检查响应,即使代码没有在某个 description
字段中添加任何内容,JSON 响应也会包含默认值 (null
)

这意味着它 **将始终具有一个值**,只是在某些情况下该值可能是 None
(或 JSON 中的 null
)。
这意味着使用您 API 的客户端不需要检查该值是否存在,他们可以 **假设该字段始终存在**,只是在某些情况下它将具有 None
的默认值。
在 OpenAPI 中描述此方法的方法是将该字段标记为 **必需的**,因为它将始终存在。
因此,模型的 JSON 架构可能不同,具体取决于它是用于 **输入还是输出**
- 对于 **输入**,
description
**不是必需的** - 对于 **输出**,它是 **必需的** (并且可能是
None
,或者用 JSON 术语来说,是null
)
文档中的输出模型¶
您也可以在文档中检查输出模型,**两者** name
和 description
都被标记为 **必需的**,并带有 **红色星号**

文档中的输入和输出模型¶
如果您检查 OpenAPI 中所有可用的架构 (JSON 架构),您将看到有两个,一个 Item-Input
和一个 Item-Output
。
对于 Item-Input
,description
**不是必需的**,它没有红色星号。
但是对于 Item-Output
,description
**是必需的**,它有一个红色星号。

有了 **Pydantic v2** 的这项功能,您的 API 文档更加 **精确**,如果您有自动生成的客户端和 SDK,它们也会更加精确,从而提供更好的 **开发人员体验** 和一致性。 🎉
不要分离模式¶
现在,在某些情况下,您可能希望对输入和输出使用相同的模式。
这可能是最主要的用例,如果您已经有一些自动生成的客户端代码/SDK,而您不想更新所有自动生成的客户端代码/SDK,您可能希望在某个时候这样做,但可能现在还不想。
在这种情况下,您可以在FastAPI中使用参数separate_input_output_schemas=False
来禁用此功能。
信息
对separate_input_output_schemas
的支持是在 FastAPI 0.102.0
中添加的。🤓
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI(separate_input_output_schemas=False)
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
app = FastAPI(separate_input_output_schemas=False)
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
app = FastAPI(separate_input_output_schemas=False)
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> List[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
文档中输入和输出模型的相同模式¶
现在,对于模型,输入和输出将只有一个模式,即Item
,并且它将具有description
作为非必需属性

这与 Pydantic v1 中的行为相同。🤓