Reputation: 3092
I'd like to use pydantic
for handling data (bidirectionally) between an api and datastore due to it's nice support for several types I care about that are not natively json-serializable. It has better read/validation support than the current approach, but I also need to create json-serializable dict
objects to write out.
from uuid import UUID, uuid4
from pydantic import BaseModel
class Model(BaseModel):
the_id: UUID
instance = Model(the_id=uuid4())
print("1: %s" % instance.dict()
print("2: %s" % instance.json()
prints
{'the_id': UUID('4108356a-556e-484b-9447-07b56a664763')}
>>> inst.json()
'{"the_id": "4108356a-556e-484b-9447-07b56a664763"}'
Id like the following:
{"the_id": "4108356a-556e-484b-9447-07b56a664763"} # eg "json-compatible" dict
It appears that while pydantic has all the mappings, but I can't find any usage of the serialization outside the standard json
~recursive encoder (json.dumps( ... default=pydantic_encoder)
) in pydantic/main.py
. but I'd prefer to keep to one library for both validate raw->obj (pydantic is great at this) as well as the obj->raw(dict) so that I don't have to manage multiple serialization mappings. I suppose I could implement something similar to the json
usage of the encoder, but this should be a common use case?
Other approaches such as dataclasses(builtin)
+ libraries such as dataclasses_jsonschema
provide this ~serialization to json-ready dict
, but again, hoping to use pydantic for the more robust input validation while keeping things symmetrical.
Upvotes: 71
Views: 148585
Reputation: 59315
The official method in Pydantic 2 is using the .model_dump()
method with mode="json"
argument:
print(instance.model_dump(mode="json"))
From the Pydantic 2 documentation
:
mode
: The mode in whichto_python
should run. If mode is'json'
, the output will only contain JSON serializable types. If mode is'python'
, the output may contain non-JSON-serializable Python objects.
Upvotes: 17
Reputation: 3092
it appears this functionality has been proposed, and (may be) favored by pydantic's author samuel colvin, as https://github.com/samuelcolvin/pydantic/issues/951#issuecomment-552463606
which proposes adding a simplify
parameter to Model.dict()
to output jsonable data.
This code runs in a production api layer, and is exersized such that we can't use the one-line workaround suggested (just doing a full serialize (.json()
) + full deserialize). We implemented a custom function to do this, descending the result of .dict()
and converting types to jsonable - hopefully the above proposed functionality is added to pydantic in the future.
Upvotes: 17
Reputation: 32233
The current version of pydantic
does not support creating jsonable dict
straightforwardly. But you can use the following trick:
Note: This is a suboptimal solution
class Model(BaseModel):
the_id: UUID = Field(default_factory=uuid4)
print(json.loads(Model().json()))
{'the_id': '4c94e7bc-78fe-48ea-8c3b-83c180437774'}
Or more efficiently by means of orjson
orjson.loads(Model().json())
There is the model_dump()
method accepting the mode
parameter.
mode: Literal['json', 'python'] | str = 'python'
If mode is 'json', the dictionary will only contain JSON serializable types.
If mode is 'python', the dictionary may contain any Python objects.
class Model(BaseModel):
the_id: UUID = Field(default_factory=uuid4)
print(Model().model_dump(mode='json'))
# {'the_id': '4c94e7bc-78fe-48ea-8c3b-83c180437774'}
Upvotes: 72
Reputation: 35
As of 18/10/2023, .model_dump()
will return a dictionary of the model. .dict()
is depreciated.
Upvotes: 2
Reputation: 2135
Another alternative is to use the jsonable_encoder
method from fastapi
if you're using that already: https://fastapi.tiangolo.com/tutorial/encoder/
The code seems pretty self-contained so you could copy paste it if the license allows it.
Upvotes: 14