Reputation: 5849
I have defined a POST call would that needs data:
{
"one" : "hello",
"two" : "world",
"three" : {
"ab": "123",
"cd": false
}
}
For this, I am able to define one
and two
, but unsure what is the right was to define three
. How can I specify a JSON field in Marshmallow? I am able to define basic fields such as:
from marshmallow import Schema, post_load, fields
class Foo(object):
def __init__(self, one, two=None):
self.one = one
self.two = two
class MySchema(Schema):
one = fields.String(required=True)
two = fields.String()
@post_load
def create_foo(self, data, **kwargs):
return Foo(**data)
How do I define three
in MySchema
? Should I:
json.loads()/json.dumps()
? Or is there a way to define it properly?fields.Dict
?Schema
for this fieldfield.Field
?I am looking at https://marshmallow.readthedocs.io/en/3.0/api_reference.html, though still not sure. A JSON sub-field or a nested JSON seems like a common use-case, yet I am not able to find anything relevant on this.
Upvotes: 11
Views: 12891
Reputation: 154735
If you want to support arbitrary nested values in the field, rather than defining a schema for them, you can use:
fields.Dict()
(to accept an arbitrary Python dict
, or, equivalently, an arbitrary JSON object), orfields.Raw()
(for arbitrary Python objects, or, equivalently, arbitrary JSON values)An example script you can run that uses both of the above, based on the example in the question:
import json
from marshmallow import Schema, fields, post_load
class Foo(object):
def __init__(self, one, two=None, three=None, four=None):
self.one = one
self.two = two
self.three = three
self.four = four
class MySchema(Schema):
one = fields.String(required=True)
two = fields.String()
three = fields.Dict()
four = fields.Raw()
@post_load
def create_foo(self, data, **kwargs):
return Foo(**data)
post_data = json.loads(
"""{
"one" : "hello",
"two" : "world",
"three" : {
"ab": "123",
"cd": false
},
"four" : 567
}"""
)
foo = MySchema().load(post_data)
print(foo.one)
print(foo.two)
print(foo.three)
print(foo.four)
Upvotes: 3
Reputation: 51904
This can be done with nested schemas: https://marshmallow.readthedocs.io/en/3.0/nesting.html
Your schema would look something like:
class MySchema(Schema):
one = fields.String(required=True)
two = fields.String()
three = fields.Nested(ThreeSchema)
class ThreeSchema(Schema):
ab = fields.String()
cd = fields.Boolean()
Upvotes: 9
Reputation: 623
You can create your own field
import json
from marshmallow import fields
class JSON(fields.Field):
def _deserialize(self, value, attr, data, **kwargs):
if value:
try:
return json.loads(value)
except ValueError:
return None
return None
...
from marshmallow import fields, Schema
from schemas.base import JSON
class ObjectSchema(Schema):
id = fields.Integer()
data = JSON()
Upvotes: 4