我正在尝试在 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
内部验证。
我做错了什么?欢迎任何提示!
这与您开始的内容略有不同,但我认为您可能想与这里的受歧视工会合作:
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
我希望这有帮助!