Reputation: 1493
I have a dynamic json like:
{
"ts": 1111111, // this field is required
... // others are dynamic
}
The fields are all dynamic except ts
. E.g:
{"ts":111,"f1":"aa","f2":"bb"}
{"ts":222,"f3":"cc","f4":"dd"}
How to declare this model with Pydantic?
class JsonData(BaseModel):
ts: int
... # and then?
Equivalent to typescript:
interface JsonData {
ts: number;
[key: string]: any;
}
Thanks.
Upvotes: 1
Views: 4154
Reputation: 3927
If type validation doesn't matter then you could use the extra
option allow
:
'allow'
will assign the attributes to the model.
class JsonData(BaseModel):
ts: int
class Config:
extra = "allow"
This will give:
data = JsonData.parse_raw("""
{
"ts": 222,
"f3": "cc",
"f4": "dd"
}
""")
repr(data)
# "JsonData(ts=222, f4='dd', f3='cc')"
And the fields can be accessed via:
print(data.f3)
# cc
However, if you could change the request body to contain an object holding the "dynamic fields", like the following:
{
"ts": 111,
"fields": {
"f1": "aa",
"f2": "bb"
}
}
or
{
"ts": 222,
"fields": {
"f3": "cc",
"f4": "dd"
}
}
you could use a Pydantic model like this one:
from pydantic import BaseModel
class JsonData(BaseModel):
ts: int
fields: dict[str, str] = {}
That way, any number of fields could be processed, while the field type would be validated, e.g.:
# No "extra" fields; yields an empty dict:
data = JsonData.parse_raw("""
{
"ts": "222"
}
""")
repr(data)
# "JsonData(ts=222, fields={})"
# One extra field:
data = JsonData.parse_raw("""
{
"ts": 111,
"fields": {
"f1": "aa"
}
}
""")
repr(data)
# "JsonData(ts=111, fields={'f1': 'aa'})"
# Several extra fields:
data = JsonData.parse_raw("""
{
"ts": 222,
"fields": {
"f2": "bb",
"f3": "cc",
"f4": "dd"
}
}
""")
repr(data)
# "JsonData(ts=222, fields={'f2': 'bb', 'f3': 'cc', 'f4': 'dd'})"
The fields can be accessed like this:
print(data.fields["f2"])
# bb
In this context, you might also want to consider the field types to be StrictStr
as opposed to str
. When using str
, other types will get coerced into strings, for example when an integer or float is passed in. This doesn't happen with StrictStr
.
See also: this workaround.
Upvotes: 5