从 json 初始化一个 pydantic 数据类
Initializing a pydantic dataclass from json
我正在将项目中现有的 dataclasses
转换为 pydantic-dataclasses
,我正在使用这些 dataclasses
来表示我需要编码到和从 json.
解析
这是我目前的方法的一个例子,它对我的用例来说不够好,我有一个 class A
我想把它都转换成一个字典(稍后转换成书面的作为 json) 并从该字典中读取。
但是我能找到将 json 解析回模型的唯一方法让我返回底层 BaseModel
而不是 dataclass
.
请注意,我正在使用 asdict
函数将 dataclass
转换为 dict
,因为它是 pydantic_encoder
用来转换 dataclass
到 json,并使用文档推荐的 pydantic_encoder
将 pydantic-dataclass
转换为 json:
https://pydantic-docs.helpmanual.io/usage/dataclasses/
from dataclasses import asdict
from pydantic.dataclasses import dataclass
from pydantic import BaseModel
@dataclass
class A:
x: str
a = A("string")
a_dict = asdict(a)
parsed_a = A.__pydantic_model__.parse_obj(a_dict)
print(f"type of a: {type(a)}")
print(f"type of parsed_a: {type(parsed_a)}")
print(f"a is instance of A: {isinstance(a, A)}")
print(f"parsed_a is instance of A: {isinstance(parsed_a, A)}")
print(f"a is instance of BaseModel: {isinstance(a, BaseModel)}")
print(f"parsed_a is instance of BaseModel: {isinstance(parsed_a, BaseModel)}")
输出:
type of a: <class '__main__.A'>
type of parsed_a: <class '__main__.A'>
a is instance of A: True
parsed_a is instance of A: False
a is instance of BaseModel: False
parsed_a is instance of BaseModel: True
有没有办法从解析的 BaseModel
初始化 A
?
我设法通过解压缩已解析 BaseModel
的属性并用它们初始化 dataclass
来解决这个问题。
此解决方案递归地适用于属性为 pydantic-dataclasses 或 primitives 的 Pydantic 数据类
请注意,此解决方案不适用于联合和泛型(目前)。
def pydantic_dataclass_from_json_dict(json_dict: dict, pydantic_dataclass_type) -> Any:
base_model = pydantic_dataclass_type.__pydantic_model__.parse_obj(json_dict)
base_mode_fields = base_model.__fields__
dataclass_fields = dataclasses.fields(pydantic_dataclass_type)
values = []
for base_model_field_name, base_model_field in base_mode_fields.items():
value = getattr(base_model, base_model_field_name)
dataclass_field = [field for field in dataclass_fields if field.name == base_model_field.name][0]
if is_dataclass(dataclass_field):
converted_value = pydantic_dataclass_from_json_dict(value, dataclass_field.type)
values.append(converted_value)
else:
values.append(value)
dataclass_object = pydantic_dataclass_type(*values)
return dataclass_object
我想我来晚了一点,但我认为这个答案对于未来有同样问题的用户可能会派上用场。
要将 dataclass
转换为 json,您可以使用您已经在使用的组合(asdict
加 json.dump
)。
from pydantic.dataclasses import dataclass
@dataclass
class User:
id: int
name: str
user = User(id=123, name="James")
d = asdict(user) # {'id': 123, 'name': 'James'
user_json = json.dumps(d)
print(user_json) # '{"id": 123, "name": "James"}'
# Or directly with pydantic_encoder
json.dumps(user, default=pydantic_encoder)
然后从原始 json
你可以使用 BaseModel
和 parse_raw
方法。
如果你想将json反序列化为pydantic
个实例,我推荐你使用parse_raw
方法:
user = User.__pydantic_model__.parse_raw('{"id": 123, "name": "James"}')
print(user)
# id=123 name='James'
否则,如果您想保留数据类:
json_raw = '{"id": 123, "name": "James"}'
user_dict = json.loads(json_raw)
user = User(**user_dict)
我正在将项目中现有的 dataclasses
转换为 pydantic-dataclasses
,我正在使用这些 dataclasses
来表示我需要编码到和从 json.
这是我目前的方法的一个例子,它对我的用例来说不够好,我有一个 class A
我想把它都转换成一个字典(稍后转换成书面的作为 json) 并从该字典中读取。
但是我能找到将 json 解析回模型的唯一方法让我返回底层 BaseModel
而不是 dataclass
.
请注意,我正在使用 asdict
函数将 dataclass
转换为 dict
,因为它是 pydantic_encoder
用来转换 dataclass
到 json,并使用文档推荐的 pydantic_encoder
将 pydantic-dataclass
转换为 json:
https://pydantic-docs.helpmanual.io/usage/dataclasses/
from dataclasses import asdict
from pydantic.dataclasses import dataclass
from pydantic import BaseModel
@dataclass
class A:
x: str
a = A("string")
a_dict = asdict(a)
parsed_a = A.__pydantic_model__.parse_obj(a_dict)
print(f"type of a: {type(a)}")
print(f"type of parsed_a: {type(parsed_a)}")
print(f"a is instance of A: {isinstance(a, A)}")
print(f"parsed_a is instance of A: {isinstance(parsed_a, A)}")
print(f"a is instance of BaseModel: {isinstance(a, BaseModel)}")
print(f"parsed_a is instance of BaseModel: {isinstance(parsed_a, BaseModel)}")
输出:
type of a: <class '__main__.A'>
type of parsed_a: <class '__main__.A'>
a is instance of A: True
parsed_a is instance of A: False
a is instance of BaseModel: False
parsed_a is instance of BaseModel: True
有没有办法从解析的 BaseModel
初始化 A
?
我设法通过解压缩已解析 BaseModel
的属性并用它们初始化 dataclass
来解决这个问题。
此解决方案递归地适用于属性为 pydantic-dataclasses 或 primitives 的 Pydantic 数据类
请注意,此解决方案不适用于联合和泛型(目前)。
def pydantic_dataclass_from_json_dict(json_dict: dict, pydantic_dataclass_type) -> Any:
base_model = pydantic_dataclass_type.__pydantic_model__.parse_obj(json_dict)
base_mode_fields = base_model.__fields__
dataclass_fields = dataclasses.fields(pydantic_dataclass_type)
values = []
for base_model_field_name, base_model_field in base_mode_fields.items():
value = getattr(base_model, base_model_field_name)
dataclass_field = [field for field in dataclass_fields if field.name == base_model_field.name][0]
if is_dataclass(dataclass_field):
converted_value = pydantic_dataclass_from_json_dict(value, dataclass_field.type)
values.append(converted_value)
else:
values.append(value)
dataclass_object = pydantic_dataclass_type(*values)
return dataclass_object
我想我来晚了一点,但我认为这个答案对于未来有同样问题的用户可能会派上用场。
要将 dataclass
转换为 json,您可以使用您已经在使用的组合(asdict
加 json.dump
)。
from pydantic.dataclasses import dataclass
@dataclass
class User:
id: int
name: str
user = User(id=123, name="James")
d = asdict(user) # {'id': 123, 'name': 'James'
user_json = json.dumps(d)
print(user_json) # '{"id": 123, "name": "James"}'
# Or directly with pydantic_encoder
json.dumps(user, default=pydantic_encoder)
然后从原始 json
你可以使用 BaseModel
和 parse_raw
方法。
如果你想将json反序列化为pydantic
个实例,我推荐你使用parse_raw
方法:
user = User.__pydantic_model__.parse_raw('{"id": 123, "name": "James"}')
print(user)
# id=123 name='James'
否则,如果您想保留数据类:
json_raw = '{"id": 123, "name": "James"}'
user_dict = json.loads(json_raw)
user = User(**user_dict)