Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pydantic convert to jsonable dict (not full json string)

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.

like image 413
some bits flipped Avatar asked Dec 09 '22 23:12

some bits flipped


2 Answers

The current version of pydantic does not support creating jsonable dict straightforwardly. But you can use the following trick:

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())
like image 120
alex_noname Avatar answered Jan 16 '23 00:01

alex_noname


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 jsonalbe 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.

like image 43
some bits flipped Avatar answered Jan 15 '23 23:01

some bits flipped