python-3.x 我可以从Pydantic获取额外的字段吗?

nvbavucw  于 2023-10-21  发布在  Python
关注(0)|答案(3)|浏览(253)

我在Pydantic Config中用extra = Extra.allow定义了一个pydantic Schema。
是否有可能获得一个列表或一组单独传递给Schema的额外字段。
例如:

from pydantic import BaseModel as pydanticBaseModel
class BaseModel(pydanticBaseModel):
    name: str

    class Config:
        allow_population_by_field_name = True
        extra = Extra.allow

下面是JSON:

{
    "name": "Name",
    "address": "bla bla",
    "post": "post"
   }

我需要一个从pydantic函数,如果可用,将返回所有额外的字段通过。喜欢:{"address", "post"}

vtwuwzda

vtwuwzda1#

来自Pydantic Docs:

额外

在模型初始化过程中是否忽略、允许或禁止额外属性。接受'ignore''allow''forbid'的字符串值,或Extra枚举的值(默认值:Extra.ignore)。如果包含额外的属性,'forbid'将导致验证失败,'ignore'将默默忽略任何额外的属性,'allow'将属性分配给模型。
这可以包含在模型Config类中,或者在继承BaseModel时作为参数。

from pydantic import BaseModel, Extra

class BaseModel(BaseModel, extra=Extra.allow):
    name: str

model = Model.parse_obj(
   {"name": "Name", "address": "bla bla", "post": "post"}
)

print(model)
# name='Name' post='post' address='bla bla'

要获得额外的值,你可以做一些简单的事情,比如将类上定义的__fields__集合与示例上__dict__中的值进行比较:

class Model(BaseModel, extra=Extra.allow):
    python_name: str = Field(alias="name")

    @property
    def extra_fields(self) -> set[str]:
        return set(self.__dict__) - set(self.__fields__)
>>> Model.parse_obj({"name": "Name", "address": "bla bla", "post": "post"}).extra_fields
{'address', 'post'}
>>> Model.parse_obj({"name": "Name", "foobar": "fizz"}).extra_fields
{'foobar'}
>>> Model.parse_obj({"name": "Name"}).extra_fields
set()
2nc8po8w

2nc8po8w2#

据我所知,没有现成的解决方案。但是,由于您可以访问pre根验证器中传递的所有“原始”数据,包括额外的字段,因此可以将它们放在单独的字典中。
例如here。感谢@PrettyWood提供:

from typing import Any, Dict, Optional

from pydantic import BaseModel, Field, root_validator

class ComposeProject(BaseModel):
    version: Optional[str] = Field(alias='version')  # just to show that it supports alias too
    extra: Dict[str, Any]

    @root_validator(pre=True)
    def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        all_required_field_names = {field.alias for field in cls.__fields__.values() if field.alias != 'extra'}  # to support alias

        extra: Dict[str, Any] = {}
        for field_name in list(values):
            if field_name not in all_required_field_names:
                extra[field_name] = values.pop(field_name)
        values['extra'] = extra
        return values

project = ComposeProject(**{
  "version": "3",
  "services": ...
})
print(project.version)  # => '3'
print(project.extra)  # => {'services': Ellipsis}
sg24os4d

sg24os4d3#

Pydantic extra fields行为在2.0版本中进行了更新。根据他们的文档,你现在不需要做任何事情,只需要将model_configextra字段设置为allow,然后可以使用model_extra字段或__pydantic_extra__示例属性来获取额外字段的dict。

from pydantic import BaseModel, Field, ConfigDict

class Model(BaseModel):
    python_name: str = Field(alias="name")

    model_config = ConfigDict(
        extra='allow',
    )

m = Model(**{"name": "Name", "address": "bla bla", "post": "post"}).model_extra
assert m == {'address': 'bla bla', 'post': 'post'}

m = Model(**{"name": "Name", "foobar": "fizz"}).__pydantic_extra__
assert m == {'foobar': 'fizz'}

m = Model(**{"name": "Name"}).__pydantic_extra__
assert m == {}

相关问题