簡體   English   中英

從 json 初始化一個 pydantic 數據類

[英]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_encoderpydantic-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您可以使用BaseModelparse_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

好的

class 定義

from pydantic import BaseModel

class Response_data(BaseModel):
    status_code: int
    text: str
    reason: str
    
    class Config:
        orm_mode = True

Json 到 BaseModel 轉換

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM