Reputation: 22661
How would I de-serialize nested JSON using marshmallow so that I can use dot notation like app.data.person.lname
? Currently my example works only one level down, but I can't get last name (lname
) from the nested person
structure:
from marshmallow import Schema, fields, post_load
import datetime as dt
import json
class Person(object):
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
class PersonSchema(Schema):
fname = fields.Str()
lname = fields.Str()
class App(object):
def __init__(self, appid, channel, person):
self.appid = appid
self.channel = channel
self.person = person
self.created_at = dt.datetime.now()
class AppSchema(Schema):
appid = fields.Str()
channel = fields.Str()
person = fields.Nested(PersonSchema)
created_at = fields.DateTime()
@post_load
def make_user(self, data):
return App(**data)
json_data = """{
"appid": "2309wfjwef",
"channel": "retail",
"person": {
"fname": "John",
"lname": "Doe"
}
}"""
app_data = json.loads(json_data)
schema = AppSchema()
app = schema.load(app_data)
print(app.data.person.lname)
Getting:
AttributeError: 'dict' object has no attribute 'lname'
Upvotes: 2
Views: 2757
Reputation: 1
in addition to Tomas Greif's last post, I get an error: TypeError: make_app() got an unexpected keyword argument 'many'
Until I added the argument to the @post_load functions like:
def make_person(self, data, **kwargs):
and
def make_app(self, data, **kwargs):
and then there was an additional error AttributeError: 'App' object has no attribute 'data', so I removed the data from the print statement:
print(app.person.fname)
AFter those changes, the code ran without errors.
Upvotes: 0
Reputation: 22661
Obviously, you need to create Person
in PersonSchema
:
from marshmallow import Schema, fields, post_load
import datetime as dt
import json
class Person(object):
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
class PersonSchema(Schema):
fname = fields.Str()
lname = fields.Str()
@post_load
def make_person(self, data):
return Person(**data)
class App(object):
def __init__(self, appid, channel, person):
self.appid = appid
self.channel = channel
self.person = person
self.created_at = dt.datetime.now()
class AppSchema(Schema):
appid = fields.Str()
channel = fields.Str()
person = fields.Nested(PersonSchema)
created_at = fields.DateTime()
@post_load
def make_app(self, data):
return App(**data)
json_data = """{
"appid": "2309wfjwef",
"channel": "retail",
"person": {
"fname": "John",
"lname": "Doe"
}
}"""
app_data = json.loads(json_data)
schema = AppSchema()
app = schema.load(app_data)
print(app.data.person.fname)
Upvotes: 2