使用 Pydantic `create_model` 验证嵌套字典

发布于 2025-01-17 22:52:10 字数 688 浏览 1 评论 0原文

我正在使用 create_model 来验证一个配置文件,该文件会遇到许多嵌套的字典。在下面的示例中,我可以验证除日出和日落的最后一个巢穴之外的所有内容。

class System(BaseModel):

    data: Optional[create_model('Data', type=(str, ...), daytime=(dict, ...))] = None

try:
    p = System.parse_obj({
        'data': {
            'type': 'solar',
            'daytime': {
                'sunrise': 5,
                'sunset': 10
            }
        }})

    print(p.dict())
    vals = p.dict()
    print(vals['data']['daytime'], type(vals['data']['daytime']['sunrise']))

except ValidationError as e:
    print(e)

我如何在 create_model 中合并嵌套字典并确保日出和日落得到验证,或者是否有其他方法来验证这一点。 ?

感谢您的反馈。

I am using create_model to validate a config file which runs into many nested dicts. In the below example i can validate everything except the last nest of sunrise and sunset.

class System(BaseModel):

    data: Optional[create_model('Data', type=(str, ...), daytime=(dict, ...))] = None

try:
    p = System.parse_obj({
        'data': {
            'type': 'solar',
            'daytime': {
                'sunrise': 5,
                'sunset': 10
            }
        }})

    print(p.dict())
    vals = p.dict()
    print(vals['data']['daytime'], type(vals['data']['daytime']['sunrise']))

except ValidationError as e:
    print(e)

How can i incorporate a nested dict in create_model and ensure sunrise and sunset are validate or is there any other way to validate this. ?

Thanks for your feedback.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

好听的两个字的网名 2025-01-24 22:52:10

目前尚不清楚您要实现的目标,所以这是我最好的猜测:

pydantic's create_model() 是在使用时使用

直到运行时才知道模型的形状。

从您的代码中,尚不清楚这是否真的有必要。

这就是我要处理的方式。

(下面的代码使用Python 3.9及以上类型提示。如果您使用的是较早版本,则可能必须替换list typing.list 和>使用键入。dict.dict。)

使用“静态”模型,

from pydantic import BaseModel, create_model
from typing import Optional

class Data(BaseModel):
    type: str
    daytime: dict[str, int] # <- explicit types in the dict, values will be coerced

class System(BaseModel):
    data: Optional[Data]

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": 1,
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)
print(repr(p))
# System(data=Data(type='solar', daytime={'sunrise': 1, 'sunset': 10}))

这将在daytime中接受整数,而不是其他类型,例如字符串。

这意味着,类似的事情:

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": "some string",
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)

将失败:

pydantic.error_wrappers.ValidationError: 1 validation error for System
data -> daytime -> sunrise
  value is not a valid integer (type=type_error.integer)

如果您想对“白天”进行更多控制,则可以为其创建一个附加模型,例如:

class Daytime(BaseModel):
    sunrise: int
    sunset: int

class Data(BaseModel):
    type: str
    daytime: Daytime

class System(BaseModel):
    data: Optional[Data]

这将如上所述,但是只有参数SunriseSunset才会被解析,并且可能在“ Daytime”内的其他所有内容都将被忽略(默认情况下)。

使用“动态”模型,

如果您确实需要动态创建模型,则可以使用类似的方法:

class System(BaseModel):
    data: Optional[
        create_model(
            "Data",
            type=(str, ...),
            daytime=(dict[str, int], ...), # <- explicit types in dict
        )
    ] = None

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": 1,
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)
print(repr(p))

将有效,而

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": "abc",
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)

将失败

pydantic.error_wrappers.ValidationError: 1 validation error for System
data -> daytime -> sunrise
  value is not a valid integer (type=type_error.integer)

It's not entirely clear what you are trying to achieve, so here's my best guess:

Pydantic's create_model() is meant to be used when

the shape of a model is not known until runtime.

From your code it's not clear whether or not this is really necessary.

Here's how I would approach this.

(The code below is using Python 3.9 and above type hints. If you're using an earlier version, you might have to replace list with typing.List and dict with typing.Dict.)

Using a "Static" Model

from pydantic import BaseModel, create_model
from typing import Optional

class Data(BaseModel):
    type: str
    daytime: dict[str, int] # <- explicit types in the dict, values will be coerced

class System(BaseModel):
    data: Optional[Data]

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": 1,
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)
print(repr(p))
# System(data=Data(type='solar', daytime={'sunrise': 1, 'sunset': 10}))

This will accept integers in daytime but not other types, like strings.

That means, something like this:

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": "some string",
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)

will fail with:

pydantic.error_wrappers.ValidationError: 1 validation error for System
data -> daytime -> sunrise
  value is not a valid integer (type=type_error.integer)

If you want more control over how "daytime" is being parsed, you could create an additional model for it, e.g.:

class Daytime(BaseModel):
    sunrise: int
    sunset: int

class Data(BaseModel):
    type: str
    daytime: Daytime

class System(BaseModel):
    data: Optional[Data]

This will work as above however, only the parameters sunrise and sunset will be parsed and everything else that might be inside "daytime" will be ignored (by default).

Using a "Dynamic" Model

If you really need to create the model dynamically, you can use a similar approach:

class System(BaseModel):
    data: Optional[
        create_model(
            "Data",
            type=(str, ...),
            daytime=(dict[str, int], ...), # <- explicit types in dict
        )
    ] = None

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": 1,
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)
print(repr(p))

will work, while

system = {
    "data": {
        "type": "solar",
        "daytime": {
            "sunrise": "abc",
            "sunset": 10
        }
    }
}

p = System.parse_obj(system)

will fail with

pydantic.error_wrappers.ValidationError: 1 validation error for System
data -> daytime -> sunrise
  value is not a valid integer (type=type_error.integer)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文