Pydantic:检测字段值是否缺失或给定为空



我希望允许用户使用PUT调用有选择地更新字段。在pydantic模型中,我将字段设为Optional。在FastAPI处理程序中,如果model属性为None,则未给出该字段,并且我不更新它。

这种方法的问题是客户端无法"空白"。某些类型不需要的字段。

特别是,我有日期字段,我希望客户端能够通过在JSON中发送null来清除。我如何检测客户端发送null或客户端根本不发送字段/值之间的差异?model属性在这两种情况下都是None。

Pydantic V1

pydantic文档描述了两个可用于模型.dict()方法的选项。

  • exclude_unset:创建模型时未显式设置的字段是否应从返回的字典中排除;默认的错误。在v1.0之前,exclude_unset被称为skip_defaults;skip_defaults现在不支持使用

  • exclude_defaults:是否应该从返回的字典中排除与其默认值相等的字段(无论是否设置);默认的错误

所以你可以创建一个带有可选字段的模型类:

from typing import Optional
from pydantic import BaseModel

class MyModel(BaseModel):
foo: Optional[int] = None
bar: Optional[int] = None

并且仍然生成一个字段显式设置为None的字典,但没有默认值:

baz = MyModel(foo=None)
assert baz.dict(exclude_unset=True) == {"foo": None}
baz = MyModel(bar=None)
assert baz.dict(exclude_unset=True) == {"bar": None}
<标题>Pydantic V2 h1> p>Pydantic V2将于2023年6月30日上市

.dict()法在V2中已被移除。为了从BaseModel实例中获取字典,必须使用model_dump()方法:

from __future__ import annotations
from pydantic import BaseModel

class MyModel(BaseModel):
foo: int | None = None
bar: int | None = None
baz = MyModel(foo=None)
assert baz.model_dump(exclude_unset=True) == {"foo": None}
baz = MyModel(bar=None)
assert baz.model_dump(exclude_unset=True) == {"bar": None}

您可以查看obj.__fields_set__是否缺少该值

from typing import Optional
from pydantic import BaseModel
class Foo(BaseModel):
first: Optional[int] = None
second: Optional[int] = None
foo = Foo.parse_raw('{"first": null}')
assert foo.first is None and foo.second is None
assert foo.__fields_set__ == {"first"}

区分提供的None和没有值的另一种方法是使用@root_validator(pre=True);例如,允许可空的非可选字段。

老实说,我不确定它是否适合你的用例,但我被各种谷歌搜索指向这里,因为它回答了你的问题标题,所以我将张贴我的答案。

的优点是它是在"模型"内部检查的。并且可以被验证,例如,通过MyModel.validate(my_dict),而不需要外部的额外断言。

from typing import Optional, root_validator
from pydantic import BaseModel

class MyModel(BaseModel):
foo: Optional[int]
bar: Optional[int]
@root_validator(pre=True)
def _check_whether_foo_present(cls, values):
if not "foo" in values:
# do something, e.g.:
raise ValueError('"foo" was not provided to the model')
return values

相关内容

最新更新