如何在数据加载时从一个模型的定义转换为另一个模型的定义



目标是:

  • 以简化列表形式或详细字典/对象形式存储数据。
  • model.Schema()定义两种格式
  • 在应用程序中使用详细对象形式的数据。

根据这个问题,我试着在爱好上定义root_validator:

#!/usr/bin/env python3.10
from pydantic import BaseModel, root_validator

H = {
"name": "Mark",
"hobbies": [
"Hobby1",
"Hobby2|Description of hobby 2"
]
}

class Hobby(BaseModel):
name: str
description: str | None

class Hobbies(BaseModel):
__root__: list[Hobby | str]
@root_validator(pre=True)
def convert_string_to_dict(cls, values):
"""
Converts strings to a dictionary, with an optional fields, divided by
'|' character.
"""
for idx, value in values:
if not isinstance(value, str):
continue
value = dict(zip(Hobby.__fields__, value.split("|", maxsplit=1)))
values[idx] = value
return values

class Hobbyst(BaseModel):
name: str
hobbies: Hobbies
hobbyst = Hobbyst(**H)
print(hobbyst.dict())

我希望脚本打印:

{'name': 'Mark', hobbies: [{'name': 'Hobby1', 'description': None}, {'name': 'Hobby2', 'description': 'Description of hobby 2'}]}

但是我得到了以下错误:

Traceback (most recent call last):
File "./playground.py", line 41, in <module>
hobbyst = Hobbyst(**H)
File "pydantic/main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Hobbyst
hobbies -> __root__
too many values to unpack (expected 2) (type=value_error)

[编辑]

我稍微修改了接受的答案:

@root_validator(pre=True)
def convert_string_to_dict(cls, values: dict):
"""
Converts strings to a dictionary, with an optional fields, divided by
'|' character.
"""
for idx, value in enumerate(values["__root__"]):
if not isinstance(value, str):
continue
value = dict(zip(Hobby.__fields__, value.split("|", maxsplit=1)))
values["__root__"][idx] = value
return values

我已经忘记了enumerate,也不知道,字典而不是列表将被传递给根验证器。

这样做怎么样?

import typing
from pprint import pformat
from pydantic import BaseModel
from pydantic import root_validator

H = {
"name": "Mark",
"hobbies": [
"Hobby1",
"Hobby2|Description of hobby 2",
{"name": "Hobby3", "description": "Description of hobby 3"},
],
}

class Hobby(BaseModel):
name: str
description: typing.Union[str, None]

class Hobbies(BaseModel):
__root__: typing.Union[typing.List[str], typing.List[Hobby]]
@root_validator(pre=True)
@classmethod
def convert_string_to_dict(cls, values: typing.Dict):
_hobbies = values.get("__root__", [])
hobbies = []
if _hobbies:
for hobbies_obj in _hobbies:
if not isinstance(hobbies_obj, str):
hobbies.append(hobbies_obj)
continue
name, *desc = hobbies_obj.split("|", maxsplit=1)
hobbies.append({"name": name, "description": desc[0] if desc else None})
values.update({"__root__": hobbies})
return values

class Hobbyst(BaseModel):
name: str
hobbies: Hobbies

hobbyst = Hobbyst(**H)
print(f"dhobbyst=n{pformat(hobbyst.dict())}")
print(f"schema=n{pformat(hobbyst.schema())}")

输出:

dhobbyst=
{'hobbies': [{'description': None, 'name': 'Hobby1'},
{'description': 'Description of hobby 2', 'name': 'Hobby2'},
{'description': 'Description of hobby 3', 'name': 'Hobby3'}],
'name': 'Mark'}
schema=
{'definitions': {'Hobbies': {'anyOf': [{'items': {'type': 'string'},
'type': 'array'},
{'items': {'$ref': '#/definitions/Hobby'},
'type': 'array'}],
'title': 'Hobbies'},
'Hobby': {'properties': {'description': {'title': 'Description',
'type': 'string'},
'name': {'title': 'Name',
'type': 'string'}},
'required': ['name'],
'title': 'Hobby',
'type': 'object'}},
'properties': {'hobbies': {'$ref': '#/definitions/Hobbies'},
'name': {'title': 'Name', 'type': 'string'}},
'required': ['name', 'hobbies'],
'title': 'Hobbyst',
'type': 'object'}

最新更新