In Pydantic I want to represent a list of items as a dictionary. In that dictionary I want the key to be the id
of the Item to be the key of the dictionary.
I read the documentation on Serialization, on Mapping types and on Sequences.
However, I didn't find a way to create such a representation.
I want these in my api to have easy access from generated api clients.
class Item(BaseModel):
uid: UUID = Field(default_factory=uuid4)
updated: datetime = Field(default_factory=datetime_now)
...
class ResponseModel:
...
print ResponseModel.model_dump()
#> {
"67C812D7-B039-433C-B925-CA21A1FBDB23": {
"uid": "67C812D7-B039-433C-B925-CA21A1FBDB23",
"updated": "2024-05-02 20:24:00"
},{
"D39A8EF1-E520-4946-A818-9FA8664F63F6": {
"uid": "D39A8EF1-E520-4946-A818-9FA8664F63F6",
"updated":"2024-05-02 20:25:00"
}
}
You can use PlainSerializer
(docs) to change the serialization of a field, e.g., to change the desired output format of datetime:
from pydantic import Field, BaseModel, PlainSerializer
from uuid import UUID, uuid4
from datetime import datetime
from typing import Annotated
CustomUUID = Annotated[
UUID, PlainSerializer(lambda v: str(v), return_type=str)
]
CustomDatetime = Annotated[
datetime,
PlainSerializer(
lambda v: v.strftime("%Y-%m-%d %H:%M:%S"), return_type=str
),
]
class Item(BaseModel):
uid: CustomUUID = Field(default_factory=uuid4)
updated: CustomDatetime = Field(default_factory=datetime.now)
Item().model_dump()
# {'uid': '7b2b8e32-15c7-48b8-9ddb-2d25cc61bc61',
# 'updated': '2024-05-03 00:13:38'}
Then you can use model_serializer
(docs) to serialize the ResponseModel
:
from pydantic import Field, BaseModel, model_serializer, PlainSerializer
from uuid import UUID, uuid4
from datetime import datetime
from typing import Annotated
CustomUUID = Annotated[
UUID, PlainSerializer(lambda v: str(v), return_type=str)
]
CustomDatetime = Annotated[
datetime,
PlainSerializer(
lambda v: v.strftime("%Y-%m-%d %H:%M:%S"), return_type=str
),
]
class Item(BaseModel):
uid: CustomUUID = Field(default_factory=uuid4)
updated: CustomDatetime = Field(default_factory=datetime.now)
class ResponseModel(BaseModel):
items: list[Item]
@model_serializer
def serialize_model(self):
return {str(item.uid): item.model_dump() for item in self.items}
ResponseModel(items=[Item() for i in range(2)]).model_dump()
# {
# "e41c4446-60e3-45c5-ab0a-a25f15febac4": {
# "uid": "e41c4446-60e3-45c5-ab0a-a25f15febac4",
# "updated": "2024-05-03 00:14:58",
# },
# "e07d4152-755a-4a0f-9312-29d343bda883": {
# "uid": "e07d4152-755a-4a0f-9312-29d343bda883",
# "updated": "2024-05-03 00:14:58",
# },
# }