[英]Initializing a pydantic dataclass from json
我正在將項目中的現有dataclasses
轉換為pydantic-dataclasses
,我正在使用這些dataclasses
來表示我需要編碼和解析 json 的模型。
這是我當前方法的一個示例,它對我的用例來說不夠好,我有一個 class A
,我想將其轉換為字典(稍后轉換為 json)並從該字典中讀取。 但是我能找到將 json 解析回 model 的唯一方法讓我返回底層BaseModel
而不是dataclass
。
請注意,我正在使用asdict
function 將dataclass
轉換為dict
,因為它是pydantic_encoder
用於將dataclass
轉換為 json 的內容,並使用文檔建議的pydantic_encoder
將pydantic-dataclass
dataclass 轉換為 json: 8810568383://5270588 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)}")
output:
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
?
我想我來晚了一點,但我認為這個答案對於未來有同樣問題的用戶來說可能會派上用場。
要將數據類轉換為dataclass
您可以使用您已經在使用的組合( 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)
我設法通過解壓縮解析的BaseModel
的屬性並用它們初始化dataclass
來解決這個問題。
此解決方案遞歸地適用於屬性為 pydantic-dataclasses 或原語的 Pydantic 數據類
請注意,此解決方案不適用於 Unions 和 Generics(尚)。
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
好吧,我嘗試了上述方法,但它是錯誤的,因為pydantic_model不是現有的 BaseModel 屬性。
所以我檢查了 class model 中的函數。我在其中找到了“parse_raw()”並嘗試了上述方法它很好用
讓我們使用 parse_raw() function
好的
from pydantic import BaseModel
class Response_data(BaseModel):
status_code: int
text: str
reason: str
class Config:
orm_mode = True
json = f(x)
response = Response_data.parse_raw(json)
print(response.dist())
然后響應只是 Json 字符串我們可以使用上述方式將 json 字符串轉換為迂腐的 BaseModel
在我看來,現在有可能以一種簡單的方式解決這個問題。 添加到@Guillem 示例:
from pydantic.dataclasses import dataclass
from pydantic.tools import parse_obj_as
import dataclasses
import json
@dataclass
class User:
id: int
name: str
user = User(id=123, name="James")
user_json = json.dumps(dataclasses.asdict(user))
print(user_json) # '{"id": 123, "name": "James"}'
user_dict = json.loads(user_json)
user = parse_obj_as(User, user_dict)
print(user) # User(id=123, name='James')
它也適用於遞歸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.