我有一些 Pydantic 模型,其字段是不同模型的联合。 我正在寻找一种方法来在我的 fastapi 生成的文档中弃用一些联合模型。
我可以通过以下方式弃用整个字段:
Field(default=None, deprecated=True)
但是我发现没有办法在其中一个可能的值上做到这一点。例如在下面的示例中,是否可以将 SimpleUser 标记为已弃用 Log 模型并根据该标记生成文档。
from typing import Union
from pydantic import BaseModel, Field
class Admin(BaseModel):
name: str
class SimpleUser(BaseModel):
age: int
class Log(BaseModel):
user: Union[Admin, SimpleUser, None] = Field(default=None)
Pydantic 通过在其他模型中定义的属性中使用
$ref
键来创建嵌套模型的模式。默认情况下,架构将有一个单独的definitions
对象,其中包含其中引用的架构。
在您的特定情况下,
Log
架构将如下所示:
{
"title": "Log",
"type": "object",
"properties": {
"user": {
"title": "User",
"anyOf": [
{
"$ref": "#/definitions/Admin"
},
{
"$ref": "#/definitions/SimpleUser"
}
]
}
},
"definitions": {
"Admin": {
"title": "Admin",
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
}
},
"required": [
"name"
]
},
"SimpleUser": {
"title": "SimpleUser",
"type": "object",
"properties": {
"age": {
"title": "Age",
"type": "integer"
}
},
"required": [
"age"
]
}
}
}
联合反映在
anyOf
键中,数组中的每个对象都引用其中一个模型。
$ref
旁边添加其他关键字。因此,我假设您可以通过简单地添加 SimpleUser
关键字以及对 user
定义的引用来传达
deprecated
是 SimpleUser
的弃用选项。
schema_extra
配置参数最终控制 JSON 模式的构建方式。如果你将它定义为内部Config
类的静态方法,你可以按照你喜欢的任何方式修改它。
所以实现该加法的方法如下所示:
from typing import Any
from pydantic import BaseModel, Field
class Admin(BaseModel):
name: str
class SimpleUser(BaseModel):
age: int
class Log(BaseModel):
user: Admin | SimpleUser | None = Field(default=None)
class Config:
@staticmethod
def schema_extra(schema: dict[str, Any]) -> None:
"""Marks the `SimpleUser` option for `user` as deprecated."""
user_property = schema["properties"]["user"]
for obj in user_property["anyOf"]:
ref = obj.get("$ref")
if isinstance(ref, str) and ref.endswith("/SimpleUser"):
obj["deprecated"] = True
break
print(Log.schema_json(indent=2))
现在的输出:
{
"title": "Log",
"type": "object",
"properties": {
"user": {
"title": "User",
"anyOf": [
{
"$ref": "#/definitions/Admin"
},
{
"$ref": "#/definitions/SimpleUser",
"deprecated": true
}
]
}
},
"definitions": {
"Admin": {
"title": "Admin",
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
}
},
"required": [
"name"
]
},
"SimpleUser": {
"title": "SimpleUser",
"type": "object",
"properties": {
"age": {
"title": "Age",
"type": "integer"
}
},
"required": [
"age"
]
}
}
}
与之前的唯一区别是添加
"deprecated": true
.
我不是 100% 确定客户是否应该按照您的预期方式理解此模式,因为我没有发现以这种方式使用它的示例,但我也没有发现相反的迹象,并且 IMO 符合规范。也许对 JSON Schema 有更多经验的人可以对此发表评论以(不)确认。
如果
$ref
旁边的附加属性被客户端忽略,因为它坚持 OpenAPI 3.1 规范,您仍然可以在整个 SimpleUser
模型上设置已弃用的属性:
from pydantic import BaseModel, Field
class Admin(BaseModel):
name: str
class SimpleUser(BaseModel):
age: int
class Config:
schema_extra = {"deprecated": True}
class Log(BaseModel):
user: Admin | SimpleUser | None = Field(default=None)