pydantic convert to jsonable dict (not full json string)

Question:

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.

Asked By: some bits flipped

||

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())
Answered By: 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.

Answered By: some bits flipped

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.

Answered By: aiguofer

The official method in Pydantic 2 (which is not released as of this answer) is using the .model_dump() method with mode="json" argument:

print(instance.model_dump(mode="json"))

From the Pydantic 2 Plan document:

def model_dump_json(self, ...) -> str:
   """
   previously `json()`, arguments as above
   effectively equivalent to `json.dump(self.model_dump(..., mode='json'))`,
   but more performant
   """
Answered By: Selcuk