【问题标题】:Using pydantic to deserialize sublasses of a model使用 pydantic 反序列化模型的子类
【发布时间】:2021-08-11 17:15:12
【问题描述】:

我正在使用遵循类继承模式的数据...我无法让 pydantic 针对某些用例正确反序列化它。

鉴于下面的代码,使用parse_* 方法时似乎没有调用验证器。 “fluffy”和“tiger”的类型是Animal,但是当反序列化“bob”Person时,他的宠物是正确的Dog类型。

还有其他方法可以解决这个问题吗?使用pydantic 不是必需的,但是能够反序列化嵌套的复杂类型(包括对象的ListDict)。

# modified from the following examples
# - https://github.com/samuelcolvin/pydantic/issues/2177#issuecomment-739578307
# - https://github.com/samuelcolvin/pydantic/issues/619#issuecomment-713508861

from pydantic import BaseModel

TIGER = """{ "type": "cat", "name": "Tiger the Cat", "color": "tabby" }"""
FLUFFY = """{ "type": "dog", "name": "Fluffy the Dog", "color": "brown", "breed": "rottweiler" }"""

ALICE = """{ "name": "Alice the Person" }"""
BOB = f"""{{ "name": "Bob the Person", "pet": {FLUFFY} }}"""

class Animal(BaseModel):
    type: str
    name: str
    color: str = None

    _subtypes_ = dict()

    def __init_subclass__(cls, type=None):
        cls._subtypes_[type or cls.__name__.lower()] = cls

    @classmethod
    def __get_validators__(cls):
        yield cls._convert_to_real_type_

    @classmethod
    def _convert_to_real_type_(cls, data):
        data_type = data.get("type")

        if data_type is None:
            raise ValueError("Missing 'type' in Animal")

        sub = cls._subtypes_.get(data_type)

        if sub is None:
            raise TypeError(f"Unsupport sub-type: {data_type}")

        return sub(**data)

class Cat(Animal, type="cat"):
    hairless: bool = False

class Dog(Animal, type="dog"):
    breed: str

class Person(BaseModel):
    name: str
    pet: Animal = None

tiger = Animal.parse_raw(TIGER)
print(f"tiger [{tiger.name}] => {type(tiger)} [{tiger.type}]")

fluffy = Animal.parse_raw(FLUFFY)
print(f"fluffy [{fluffy.name}] => {type(fluffy)} [{fluffy.type}]")

bob = Person.parse_raw(BOB)
pet = bob.pet
print(f"bob [{bob.name}] => {type(bob)}")
print(f"pet [{pet.name}] => {type(pet)}")

输出:

tiger [Tiger the Cat] => <class '__main__.Animal'>
fluffy [Fluffy the Dog] => <class '__main__.Animal'>
bob [Bob the Person] => <class '__main__.Person'>
pet [Fluffy the Dog] => <class '__main__.Dog'>

【问题讨论】:

    标签: python pydantic


    【解决方案1】:

    pydantic project discussion的回答:

    你可以简单地添加

    class Animal(BaseModel):
        ...
        
        @classmethod
        def parse_obj(cls, obj):
            return cls._convert_to_real_type_(obj)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      相关资源
      最近更新 更多