schema嵌套
schema可以嵌套使用以表示对象间的关系(如外键关系)。
例如下例中Blog有一个用User对象表示的author属性:
代码语言:javascript复制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
使用Nested
子类接收嵌套的schema表示二者的关系:
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)
序列化后的blog对象将包含嵌套的user对象:
代码语言:javascript复制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'}}
如果field嵌套对象是一个集合,必须设置many=True
,如collaborators = fields.Nested(UserSchema, many=True)
指定嵌套对象的序列化字段
设置only
参数显式地指定对嵌套对象的哪些属性进行序列化:
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'}
# }
使用点分隔符可以表示深层嵌套对象的属性:
代码语言:javascript复制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'}
# }
# }
如果给only
参数传递的是字符串(上面的例子传递的是列表),将返回单个值(上面的例子返回的是键值映射)或值的列表(需要设置many=True
):
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"]
# }
双向嵌套
对于两个互相嵌套的对象,可以使用类名引用嵌套的schema,即便是引用时该schema还没有被定义。
在下面的例子中,Author和Book对象是一对多的关系:
代码语言:javascript复制class AuthorSchema(Schema):
# 必须使用only或exclude参数避免无限递归
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')
代码语言:javascript复制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"
# }
# ]
# }
也可以使用导入模块的方式传递嵌套schema,如books = fields.Nested('path.to.BookSchema', many=True, exclude=('author', ))
schema自嵌套
给Nested传递字符串参数self
表示和对象本身的关系:
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": []
# }
# }