Pydantic 的基本模型中不需要

问题描述 投票:0回答:1

我尝试从 API 接受数据,然后使用 Pydantic 基本模型验证响应结构。但是,我遇到的情况是,有时某些字段不会包含在响应中,而有时会包含在响应中。问题是,当我尝试验证结构时,Pydantic 开始抱怨这些字段“丢失”,尽管它们有时可能会丢失。我真的不明白如何将一个字段定义为“missible”。文档提到,仅定义为名称和类型的字段被认为是这种方式,但我没有任何运气

这是我想要实现的目标的一个简单示例

# Response: {a: 1, b: "abc", c: ["a", "b", "c"]}
response: dict = json.loads(request_response)

# Pydantic Base Model
from pydantic import BaseModel
class Model(BaseModel):
   a: int
   b: str
   c: List[str]
   d: float

# Validating 
Model(**response)

# Return: ValidationError - Missing "d" field

如何使“d”不会导致验证抛出错误?我尝试将“d”切换为

d: Optional[float]
d: Optional[float] = 0.0
,但没有任何效果。

谢谢!

python python-typing pydantic typing
1个回答
7
投票

Pydantic v2

模型要么有字段,要么没有。从某种意义上说,字段“总是”需要在完全初始化的模型实例上具有值。只是如果在初始化期间没有显式提供值,则字段可能会有一个将分配给它的“default”值。 (请参阅文档中的基本模型用法 您面临的问题最终是:如果未明确设置,应为字段 d 分配什么值?它应该是

None

还是应该是某个默认的

float
值(例如
0.
)还是其他值?无论您选择什么,都必须在模型定义中指定默认值,并记住使用正确的类型注释字段。
如果您选择默认的 
float
(例如

0.

),您的类型保持不变,只需将字段定义为

d: float = 0.
。如果您希望默认值是不同类型,例如
None
,则需要将定义更改为
d: float | None = None
为了完整起见,您还可以定义一个
默认工厂
而不是静态值,以便在初始化期间计算实际值。

这是一个简短的演示: from pydantic import BaseModel, Field, ValidationError class Model(BaseModel): a: int b: str c: list[str] d: float | None = None # equivalent: `d: typing.Optional[float] = None` e: float = 0. f: float = Field(default_factory=lambda: 420.69) if __name__ == '__main__': instance = Model.model_validate({ "a": 1, "b": "abc", "c": ["a", "b", "c"], }) print(instance.model_dump_json(indent=4)) try: Model.model_validate({ "a": 1, "b": "abc", "c": ["a", "b", "c"], "d": None, # fine "e": None, # error "f": None, # error }) except ValidationError as e: print(e.json(indent=4))

输出:

{
    "a": 1,
    "b": "abc",
    "c": [
        "a",
        "b",
        "c"
    ],
    "d": null,
    "e": 0.0,
    "f": 420.69
}

[ { "type": "float_type", "loc": [ "e" ], "msg": "Input should be a valid number", "input": null, "url": "https://errors.pydantic.dev/2.7/v/float_type" }, { "type": "float_type", "loc": [ "f" ], "msg": "Input should be a valid number", "input": null, "url": "https://errors.pydantic.dev/2.7/v/float_type" } ]

[旧答案]Pydantic v1
正如@python_user所说,你的建议都有效。

诚然,

typing.Optional

对于 Pydantic 场的行为记录很少。也许是因为它被认为是显而易见的。我个人认为这并不明显,因为

Optional[T]

相当于

Union[T, None]
(或新符号中的
T | None
)。
使用任何其他类型的联合注释字段,同时省略默认值将导致该字段为必填字段。但如果您使用包含 
None
的并集进行注释,则该字段会自动接收

None

默认值。有点不一致,但就是这样。

但是,问题最终是您希望模型字段是什么。如果未明确设置,应为字段 
d
分配什么值?它应该是

None

还是应该是某个默认的

float
值? (例如
0.
)如果
None
可以,那么您可以使用
Optional[float]
float | None
,并且不需要指定默认值。 (指定
Optional[float] = None
是等效的。)如果您想要任何其他默认值,则需要相应地指定它,例如
d: float = 0.0
;但在这种情况下,
None
将是该字段的
无效
值。
from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    a: int
    b: str
    c: list[str]
    d: float | None  # or typing.Optional[float]
    e: float = 0.


if __name__ == '__main__':
    print(Model.parse_obj({
        "a": 1,
        "b": "abc",
        "c": ["a", "b", "c"],
    }), "\n")
    try:
        Model.parse_obj({
            "a": 1,
            "b": "abc",
            "c": ["a", "b", "c"],
            "e": None,
        })
    except ValidationError as e:
        print(e)

输出:

a=1 b='abc' c=['a', 'b', 'c'] d=无 e=0.0

模型有 1 个验证错误
e
  none 不是允许的值 (type=type_error.none.not_allowed)

© www.soinside.com 2019 - 2024. All rights reserved.