schema Nesting
Schemas can be nested to represent relationships between objects, such as foreign key relationships.
For example, in the following example, Blog has an author attribute represented by a User object:
import datetime as dt class User(object): def __init__(self, name, email): self.name = name self.email = email self.created_at = dt.datetime.now() self.friends = [] self.employer = None class Blog(object): def __init__(self, title, author): self.title = title self.author = author # A User object
Receiving nested schema s using the Nested subclass represents the relationship between the two:
from marshmallow import Schema, fields, pprint class UserSchema(Schema): name = fields.String() email = fields.Email() created_at = fields.DateTime() class BlogSchema(Schema): title = fields.String() author = fields.Nested(UserSchema)
The serialized blog object will contain nested user objects:
user = User(name="Monty", email="monty@python.org") blog = Blog(title="Something Completely Different", author=user) result = BlogSchema().dump(blog) pprint(result) # {'title': u'Something Completely Different', # 'author': {'name': u'Monty', # 'email': u'monty@python.org', # 'created_at': '2014-08-17T14:58:57.600623+00:00'}}
If a field nested object is a collection, you must set many=True, such as collaborators = fields.Nested(UserSchema, many=True)
Specify serialization fields for nested objects
Setting the only parameter explicitly specifies which properties of the nested object are serialized:
class BlogSchema2(Schema): title = fields.String() author = fields.Nested(UserSchema, only=["email"]) schema = BlogSchema2() result = schema.dump(blog) pprint(result) # { # 'title': u'Something Completely Different', # 'author': {'email': u'monty@python.org'} # }
The attributes of deeply nested objects can be represented by point separators:
class SiteSchema(Schema): blog = fields.Nested(BlogSchema2) schema = SiteSchema(only=['blog.author.email']) result, errors = schema.dump(site) pprint(result) # { # 'blog': { # 'author': {'email': u'monty@python.org'} # } # }
If the only parameter is passed a string (the example above passes a list), a single value (the example above returns a key-value mapping) or a list of values (many=True needs to be set):
class UserSchema(Schema): name = fields.String() email = fields.Email() friends = fields.Nested('self', only='name', many=True) # ... create ``user`` ... result, errors = UserSchema().dump(user) pprint(result) # { # "name": "Steve", # "email": "steve@example.com", # "friends": ["Mike", "Joe"] # }
Bidirectional Nesting
For two objects nested within each other, the nested schema can be referenced using the class name even if it is not defined at the time of reference.
In the following example, Author and Book objects are one-to-many relationships:
class AuthorSchema(Schema): # The only or exclude parameter must be used to avoid infinite recursion books = fields.Nested('BookSchema', many=True, exclude=('author', )) class Meta: fields = ('id', 'name', 'books') class BookSchema(Schema): author = fields.Nested(AuthorSchema, only=('id', 'name')) class Meta: fields = ('id', 'title', 'author')
from marshmallow import pprint from mymodels import Author, Book author = Author(name='William Faulkner') book = Book(title='As I Lay Dying', author=author) book_result, errors = BookSchema().dump(book) pprint(book_result, indent=2) # { # "id": 124, # "title": "As I Lay Dying", # "author": { # "id": 8, # "name": "William Faulkner" # } # } author_result, errors = AuthorSchema().dump(author) pprint(author_result, indent=2) # { # "id": 8, # "name": "William Faulkner", # "books": [ # { # "id": 124, # "title": "As I Lay Dying" # } # ] # }
Nested schema s can also be passed by importing modules, such as books = fields.Nested('path.to.BookSchema', many=True, exclude=('author',))
schema self-nesting
Pass the string parameter self to Nested to represent the relationship to the object itself:
class UserSchema(Schema): name = fields.String() email = fields.Email() friends = fields.Nested('self', many=True) # Use the 'exclude' argument to avoid infinite recursion employer = fields.Nested('self', exclude=('employer', ), default=None) user = User("Steve", 'steve@example.com') user.friends.append(User("Mike", 'mike@example.com')) user.friends.append(User('Joe', 'joe@example.com')) user.employer = User('Dirk', 'dirk@example.com') result = UserSchema().dump(user) pprint(result.data, indent=2) # { # "name": "Steve", # "email": "steve@example.com", # "friends": [ # { # "name": "Mike", # "email": "mike@example.com", # "friends": [], # "employer": null # }, # { # "name": "Joe", # "email": "joe@example.com", # "friends": [], # "employer": null # } # ], # "employer": { # "name": "Dirk", # "email": "dirk@example.com", # "friends": [] # } # }