some bits flipped
some bits flipped

Reputation: 3092

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.

Upvotes: 71

Views: 148585

Answers (5)

Selcuk
Selcuk

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 which to_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

some bits flipped
some bits flipped

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

alex_noname
alex_noname

Reputation: 32233

Pydantic 1.x (old answer)

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())

Pydantic 2

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

user7888294
user7888294

Reputation: 35

As of 18/10/2023, .model_dump() will return a dictionary of the model. .dict() is depreciated.

Upvotes: 2

aiguofer
aiguofer

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

Related Questions