lapots
lapots

Reputation: 13405

deserialize json array field into an object using pydantic

I have an object, that has an inner object with custom serializer

class ParameterModel(BaseModel):
    size_x: int
    size_y: int

    @model_serializer
    def ser_model(self) -> list:
        return [self.size_x, self.size_y]

class ObjectModel(BaseModel):
    name: str
    parameters: ParameterModel

So when I create this object and serialize it, the result looks like this

o_m = ObjectModel(name='Cube', parameters=ParameterModel(size_x=10, size_y=10))
o_m_json = o_m.model_dump_json()
print(o_m.model_dump_json()) # {"name":"Cube","parameters":[10,10]}

But now I want to deserialize that type of input. When I try using

ObjectModel.model_validate_json(o_m_json)

I get the error

Input should be an object [type=model_type, input_value=[10, 10], input_type=list]

So, as far as I understand, due to the source being a list it does not match with the expected object type. But is there a way to tell Pydantic that this field should be deserialized into an object?

Upvotes: 1

Views: 1062

Answers (1)

lapots
lapots

Reputation: 13405

As a solution I went with a custom before validator

class ParameterModel(BaseModel):
    size_x: int
    size_y: int

    @model_serializer
    def ser_model(self) -> list:
        return [self.size_x, self.size_y]
    
    @staticmethod
    def before_transformation(v: Any, info: ValidationInfo) -> ParameterModel:
        if info.mode == 'json':
            return ParameterModel(size_x=v[0], size_y=v[1])
        return v

class ObjectModel(BaseModel):
    name: str
    parameters: Annotated[ParameterModel, BeforeValidator(ParameterModel.before_transformation)]

And now when I serialize

o_m = ObjectModel(name='Cube', parameters=ParameterModel(size_x=10, size_y=10))
json_str = o_m.model_dump_json()
print(json_str) # {"name":"Cube","parameters":[10,10]}

And deserialize

print(ObjectModel.model_validate_json(json_str)) 

it produces a proper object.

Upvotes: 0

Related Questions