如何在 Pydatic 中使用 @field_validator 验证自定义编码数据?

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

我正在尝试在 Pydantic (V2) 中使用自定义编码器和解码器。我的目标是将另一个类的引用转换为其名称,而不是对整个类及其所有子类进行编码,并在 JSON 解码时将其解析回类实例。示例:

from pydantic import BaseModel, field_validator, ValidationInfo

class B(BaseModel):
    id: str
    value: int

class A(BaseModel):
    id: str
    ref: B

    class Config:
        json_encoders = {
            B: lambda t: f'{t.id}',
        }
    
    @classmethod
    @field_validator("ref", mode="before")
    def map_ref(cls, v: str, info: ValidationInfo) -> B:
        return Bs[v]

b1 = B(id="B1", value=1)
b2 = B(id="B2", value=2)
Bs = { "B1" : b1, "B2" : b2}

a1 = A(id="A1", ref=b1)
a1d = a1.model_dump_json()
print("JSON: ", a1d)

a1r = A.model_validate_json(a1d)
print("Recon: ", a1r)

输出为:

JSON:  {"id":"A1","ref":"B1"}
Traceback (most recent call last):
  File "d:\Projects\2022 NeoCity MeDT\medtproofofconcept\AppServer\custom_deserialize_test.py", line 29, in <module>
    a1r = A.model_validate_json(a1d)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Projects\2022 NeoCity MeDT\medtproofofconcept\.venv\Lib\site-packages\pydantic\main.py", line 531, in model_validate_json
    return cls.__pydantic_validator__.validate_json(json_data, strict=strict, context=context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for A
ref
  Input should be an object [type=model_type, input_value='B1', input_type=str]
    For further information visit https://errors.pydantic.dev/2.3/v/model_type

因此编码有效,它只打印

id
,而不是整个模型。但是解码会引发错误,当我调试它时,我的自定义验证器永远不会被调用,即使它被标记为运行
before
内部验证。

我做错了什么?欢迎任何提示!

python validation types pydantic
1个回答
0
投票

这与您开始的内容略有不同,但我认为您可能想与这里的受歧视工会合作:

from pydantic import BaseModel,  model_serializer, Field
from typing import Annotated, Union, Literal

class B(BaseModel):
    id: str

    @model_serializer()
    def serialize(self) -> str:
        return {"id": self.id}

class B1(B):
    id: Literal["B1"] = "B1"
    value: int = 1
    

class B2(B):
    id:  Literal["B2"] = "B2"
    value: int = 2


class A(BaseModel):
    id: str
    ref: Annotated[Union[B1, B2], Field(discriminator="id")]


a1 = A(id="A1", ref=B1())
a1d = a1.model_dump_json()
print("JSON: ", a1d)

a1r = A.model_validate_json(a1d)
print("Recon: ", a1r)

哪个打印:

JSON:  {"id":"A1","ref":{"id":"B1"}}
Recon:  id='A1' ref=B1(id='B1', value=1)

因此,您不需要处理

B
的不同实例,而是使用具有不同默认值的
B
子类。

您可以在这里找到有关受歧视工会的更多信息:https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions

我希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.