Pydantic - Pass objects to Nested model

39 views Asked by At

I have the following models:

from pydantic import BaseModel


class OrderModel(BaseModel):
    id: int
    title: str
    
    class ConfigDict:
        from_attributes = True

class ItemModel(BaseModel):
    id: int
    description: str

    class ConfigDict:
        from_attributes = True


class ResponseModel(BaseModel):
    order: OrderModel
    items: list[ItemModel]

And my objects are:

order = SqlAlchemySession.query(Order).first()
items = SqlAlchemtSession.query(Item).all()

I want to use ResponseModel to return data for users (in a FastAPI project). but I don't know how can I do that. I tested the following and it works. But I need a way that has better performance. I think For Loop is not fine for performance:

ResponseModel(
        order=OrderModel(**order.__dict__),
        items=[ItemModel(**item.__dict__) for item in items]
    )

how can I do that without For Loop?

Is there any way to use as follows?

response_model = ResponseModel(order=order, items=items)

1

There are 1 answers

0
Yurii Motov On

The solution is:

res = ResponseModel.model_validate({"order": order, "items": items})

Example:

from dataclasses import dataclass

from pydantic import BaseModel, ConfigDict


@dataclass
class Order:
    id: int
    title: str


@dataclass
class Item:
    id: int
    description: str


class OrderModel(BaseModel):
    id: int
    title: str

    model_config = ConfigDict(from_attributes=True)


class ItemModel(BaseModel):
    id: int
    description: str

    model_config = ConfigDict(from_attributes=True)


class ResponseModel(BaseModel):
    order: OrderModel
    items: list[ItemModel]


o = Order(id=1, title="order title")
items = [Item(id=i, description=f"item {i}") for i in range(3)]


res = ResponseModel.model_validate({"order": o, "items": items})

print(res)

Output:

order=OrderModel(id=1, title='order title') items=[ItemModel(id=0, description='item 0'), ItemModel(id=1, description='item 1'), ItemModel(id=2, description='item 2')]