在任意类中声明 Pydantic V2 Json 序列化逻辑

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

我正在将 Pydantic v1 代码库升级到 Pydantic V2。

Pydantic 有多种方法可以为任意 python 对象(即不从 BaseModel 等基本 pydantic 成员继承的类的实例)创建自定义序列化逻辑

但是,v1 Config.json_encoder 模式的弃用带来了一些挑战。

也就是说,客户端 BaseModel 类可以以多种方式使用任意 Python 类 Animal,只需声明一个 json 编码器。 示例:

class Animal:
    def __init__(self, name):
        self.name = name

class Zoo(BaseModel):
    first_animal: Animal
    kennel: Dict[str, Animal]
    class Config:
        json_encoders = {
            Animal: lambda v: "standard critter"
        }

其优点是确保模型中的任何 Animal 类型属性都可以使用提供的函数进行序列化。

下面的示例让我可以使用自定义逻辑来 json 序列化 Rock 类型成员的实例(RockBase 类已经具有当前代码库使用的类似 pydantic 的属性):

from typing import Annotated
from pydantic.functional_serializers import PlainSerializer
from pydantic import BaseModel, ConfigDict
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler
from pydantic_core import CoreSchema, core_schema

class RockBase:
    def __init__(self, value):
        self.value = value

    @classmethod
    def __get_pydantic_core_schema__(
        cls, source_type: Any, handler: GetCoreSchemaHandler
    ) -> CoreSchema:
        return core_schema.general_plain_validator_function(cls.validate)

    @classmethod
    def __get_pydantic_json_schema__(
        cls, _core_schema: CoreSchema, handler: GetJsonSchemaHandler
    ) -> Dict[str, Any]:
        extra_json_base = {"type": "string"}  
        return extra_json_base   

    @classmethod
    def validate(cls, v=None, *args, **kwargs):
        # validation logic
        return v

Rock = Annotated[
    RockBase,
    PlainSerializer(lambda x: "a_string", return_type=str, when_used="always")
]

class SimpleAsteroid(BaseModel):
    contains: Rock
    model_config = ConfigDict(arbitrary_types_allowed=True)

mm1 = SimpleAsteroid(contains=Rock("gravel"))
print(mm1.model_dump_json())

但是,我正在使用的代码库包含几个 pydantic 模型,它们可以实例化任意嵌套结构。

例如,此调用也应该产生可序列化的对象:

SimpleAsteroid(contains={"extra":{"nested":{"value": Rock("it's deep")}}})

我可以声明以下模型来进行实例化:

class SimpleAsteroid(BaseModel):
    contains: Any
    model_config = ConfigDict(arbitrary_types_allowed=True)

但是序列化是不可能的,因为对 model_dump_json() 的调用将失败

pydantic_core._pydantic_core.PydanticSerializationError:无法序列化未知类型:类'__main__.RockBase'

有没有办法让序列化逻辑在RockBase基类中可用,并让pydantic根据需要发现它?

python json serialization pydantic
1个回答
0
投票

似乎实现 Pydantic 的人意识到

json_encoders
和新的序列化逻辑之间没有 1:1 对应关系,他们暂时恢复了
json_encoders
选项(我正在查看 2.5 版本)

参见2.5版本中的注释

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