For bugs/questions:
Ubuntu 19.043.7.30.30.1Hi, based on one of your examples let's say I have this
from datetime import datetime
from typing import List
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: datetime = None
friends: List[int] = []
The thing is I want to be to serialize a list of users, like this one:
users_list = [
{'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']},
{'id': '456', 'signup_ts': '2017-06-02 12:22', 'friends': ['you']},
]
But the only way I found to be able to do it, was by creating a second class to nest User as a list inside,
class UserList(BaseModel):
users: List[User]
But I don't want my response nested inside a users key, I want my response just to be the list, so I can paginate it, etc. Normally, using drf this can be achieved by setting many=True when instantiating the serializer:
serializer = UserSerializer(data=users_list, many=True)
users = serializer.data
Is there a pydantic way to achieve this like I would with drf?
(Of course, this is a simple example, the real scenario will be to use Django ORM to query all objects and serialize them, but for simplicity I will stick to a simpler example)
The "right" way to do this in pydantic is to make use of "Custom Root Types". You still need to make use of a container model:
class UserList(BaseModel):
__root__: List[User]
but then the following will work:
UserList.parse_obj([
{'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']},
{'id': '456', 'signup_ts': '2017-06-02 12:22', 'friends': ['you']},
])
(and will put the values inside the __root__ property).
Unfortunately, I think there is not good serialization support for this yet, so I think when you go to return the results, if you want to return just a list you'll still need to return UserList.__root__.
I don't think there is currently a unified interface that gets you a serialized/unstructured version of the model that respects the __root_model__, but if this is what you are looking for, it could be worth building.
Thank you @dmontagu !
So based on what you suggested, I ended up with this:
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = MyModelList.parse_obj(page)
return self.get_paginated_response(dict(serializer)['__root__'])
serializer = MyModelList.parse_obj(list(queryset.values()))
return Response(dict(serializer)['__root__'])
This actually works well with Django + DRF using a ListCreateAPIView class-based view and it returns a proper paginated response from a Django QuerySet.
Maybe this isn't an optimal way to integrate it with DRF, but still is a working proof of concept.
Most helpful comment
The "right" way to do this in pydantic is to make use of "Custom Root Types". You still need to make use of a container model:
but then the following will work:
(and will put the values inside the
__root__property).Unfortunately, I think there is not good serialization support for this yet, so I think when you go to return the results, if you want to return just a list you'll still need to return
UserList.__root__.I don't think there is currently a unified interface that gets you a serialized/unstructured version of the model that respects the
__root_model__, but if this is what you are looking for, it could be worth building.