I have a pydantic model as follows.
from pydantic import Json, BaseModel
class Foo(BaseModel):
id: int
bar: Json
Foo.bar can parse JSON string as input and store it as a dict which is nice.
foo = Foo(id=1, bar='{"foo": 2, "bar": 3}')
type(foo.bar) #outputs dict
And if i want the entire object to be a dict I can do
foo.dict()
#outputs
{'id': 1, 'bar': {'foo': 2, 'bar': 3}}
But how can I export bar as JSON string as following
{'id': 1, 'bar': '{"foo": 2, "bar": 3}'}
I want to write JSON back into the database.
Pydantic author here.
There's currently no way to do that without calling json.dumps(foo.bar). You could make that a method on Foo if you liked, which would be easier to use but require the same processing.
If performance is critical, or you need the exact same JSON string you started with (same spaces etc.) You could do one of the following:
bar a string field but add a validator to check it's valid JSONI faced same problem so here comes a little hacky solution with class factory (some elegant one with something like foo: JsonVal[T] is almost impossible to implement due to numerous internal pydantic hacks like how it works with generic type annotations). Unfortunately type inference is not working, but validation and access to parsed value are ok, considering that Fields are always stored/serialized as str.
from abc import ABC
from typing import TypeVar, Generic, Type
from pydantic import Json, parse_obj_as, BaseModel
T = TypeVar('T')
class JsonVal(Generic[T], str, ABC):
@property
def parsed(self) -> T:
return None
def json_val(t: Type) -> Type[JsonVal[T]]:
class _JsonVal(JsonVal, str):
_t: Type
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
parse_obj_as(Json[cls._t], v)
return cls(v)
@property
def parsed(self):
return parse_obj_as(Json[self._t], self)
_JsonVal._t = t
return _JsonVal
class Bar(BaseModel):
bar: str
class Model(BaseModel):
foo: json_val(list[int])
bar: json_val(Bar)
m = Model.parse_obj({"foo": '[1,2,3]', "bar": '{"bar":"baz"}'})
print(m)
print(m.foo, type(m.foo), m.foo.parsed, type(m.foo.parsed))
print(m.bar, type(m.bar), m.bar.parsed, type(m.bar.parsed))
print(m.json())
# foo='[1,2,3]' bar='{"bar":"baz"}'
# f[1,2,3] <class '__main__.json_val.<locals>._JsonVal'> [1, 2, 3] <class 'list'>
# f{"bar":"baz"} <class '__main__.json_val.<locals>._JsonVal'> bar='baz' <class '__main__.Bar'>
# f{"foo": "[1,2,3]", "bar": "{\"bar\":\"baz\"}"}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With