如何从 JSON 反序列化嵌套 Pydantic 模型,其中嵌套模型保存在计算字段的列表中

问题描述 投票:0回答:1

我有一个代表持有交易的银行账户的 Pydantic 模型,它们本身就是嵌套在账户模型上的模型。交易保存在隐藏字段的列表中,并通过在 setter 方法中应用一些检查的计算字段进行访问。

简化模型:

class Account(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    owner: Customer
    _transactions: List[Transaction] = list()

    @fields.computed_field()
    @property
    def transactions(self) -> List[Transaction]:
        return self._transactions

    @transactions.setter
    def transactions(self, list_: List[Transaction]) -> None:
        # DO SOME CHECKS
        self._transactions = sorted_list

class Transaction(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    date: datetime.date = Field(frozen=False)
    amount: PositiveFloat = Field(frozen=False)

class Customer(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    name: datetime.date = Field(frozen=False)

连载

我可以成功将帐户序列化为 JSON,包括交易:

x = my_account.model_dump_json()
x

格式化输出:

'{
    "id":"1eeed00b-3bd7-48fa-ab6a-6979618ef723",
    "owner":{      
        "id":"0cad242dad03-492b-9c6b-86f0b75f9c00",
        "name":"Bob"
    },
    "transactions":[
    {"id":"42738f1d-e998-4add-94b8-713afe25b525","date":"2012-01-01","amount":1.0}
  ]
}'

反序列化(意外行为)

但是,当我尝试从 JSON 字符串重建模型时,交易字段为空。拥有嵌套客户模型的所有者字段没有问题:

Account.model_validate_json(x)

格式化输出:

Account(
    id=UUID('1eeed00b-3bd7-48fa-ab6a-6979618ef723'), 
    owner=Customer(
        id=UUID('0cad242d-ad03-492b-9c6b-86f0b75f9c00'), 
        name='Bob'
    ), 
    transactions=[]
)

有没有办法使计算字段的序列化过程可逆?

python deserialization pydantic
1个回答
0
投票

您可以使用模型验证器来做到这一点:

    @model_validator(mode="before")
    @classmethod
    def validate_model(self, data: Any):
        if isinstance(data, dict):
            self.transactions = data.get("transactions", [])
        return data

完整代码示例:

import datetime
from typing import Any, List
from uuid import UUID, uuid4

from pydantic import (BaseModel, Field, PositiveFloat, computed_field,
                      model_validator)


class Transaction(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    date: datetime.date = Field(frozen=False)
    amount: PositiveFloat = Field(frozen=False)

class Customer(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    name: str = Field(frozen=False)

class Account(BaseModel):
    id: UUID = Field(default_factory=uuid4)
    owner: Customer
    _transactions: List[Transaction] = list()

    @model_validator(mode="before")
    @classmethod
    def validate_model(self, data: Any):
        if isinstance(data, dict):
            self.transactions = data.get("transactions", [])
        return data



    @computed_field()
    @property
    def transactions(self) -> List[Transaction]:
        return self._transactions

    @transactions.setter
    def transactions(self, list_: List[Transaction]) -> None:
        # DO SOME CHECKS
        self._transactions = sorted(list_, key=lambda a, b: a.amount>b.amount)



a = Account.model_validate({
  "id": uuid4().hex,
    "owner":{      
        "id":uuid4().hex,
        "name":"Bob"
    },
    "transactions":[
    {"id":uuid4().hex,"date":"2012-01-01","amount":1.0}
  ]
})


print(a.model_dump())

输出:

{'id': UUID('0f7f32a1-b3b9-40e8-a35d-e662e5e4032e'), 'owner': {'id': UUID('bca37eaa-086a-4adf-b51c-e05feb812e9b'), 'name': 'Bob'}, 'transactions': [{'id': '87042f4e738a4b24888e6c126260edc3', 'date': '2012-01-01', 'amount': 1.0}]}
© www.soinside.com 2019 - 2024. All rights reserved.