marshmallow关系处理
- Nesting Schemas
当模型间拥有关系,比如外键,schema如何处理呢?例如:blog和user之间的关系
1 class User(object): 2 def __init__(self, name, email): 3 self.name = name 4 self.email = email 5 self.created_at = dt.datetime.now() 6 self.friends = [] 7 self.employer = None 8 9 class Blog(object): 10 def __init__(self, title, author): 11 self.title = title 12 self.author = author
使用Nested字段来代表关系,并传入相应的schema类
1 from marshmallow import Schema, fields 2 3 class UserSchema(Schema): 4 name = fields.String() 5 email = fields.Email() 6 created_at = fields.DateTime() 7 8 class BlogSchema(Schema): 9 title = fields.String() 10 author = fields.Nested(UserSchema)
序列化blog对象则会嵌入user描述
1 from marshmallow import Schema, fields, pprint 2 3 user = User2(name="Monty", email="monty@python.org") 4 blog = Blog(title="Something Completely Different", author=user) 5 pprint(BlogSchema().dump(blog)) 6 7 {'author': {'created_at': '2019-11-14T15:28:09.212278', 8 'email': 'monty@python.org', 9 'name': 'Monty'}, 10 'title': 'Something Completely Different'}
注意:如果field是多个嵌入对象的集合,则必须设置many=True
collaborators = fields.Nested(UserSchema, many=True)
- Specifying Which Fields to Nest
如果想指定序列化时嵌入对象的某几个字段,可以设置only参数
1 class BlogSchema(Schema): 2 title = fields.String() 3 author = fields.Nested(UserSchema, only=["email"]) 4 5 user = User(name="Monty", email="monty@python.org") 6 blog = Blog(title="Something Completely Different", author=user) 7 pprint(BlogSchema().dump(blog)) 8 9 {'author': {'email': 'monty@python.org'}, 10 'title': 'Something Completely Different'}
如果有更深度的嵌套,可以使用“.”符号连接
1 class Site(object): 2 def __init__(self, blog): 3 self.blog = blog 4 5 class SiteSchema(Schema): 6 blog = fields.Nested(BlogSchema) 7 8 user = User(name="Mike", email="mike@python.org") 9 blog = Blog(title="something is wrong", author=user) 10 site = Site(blog=blog) 11 schema = SiteSchema(only=['blog.author.email']) 12 pprint(schema.dump(site)) 13 14 {'blog': {'author': {'email': 'mike@python.org'}}}
使用Pluck字段可以用单个值来替换嵌套的数据
1 class UserSchema(Schema): 2 name = fields.String() 3 email = fields.Email() 4 friends = fields.Pluck("self", "name", many=True) 5 6 user1 = User(name="Mike", email="mike@example.com") 7 user2 = User(name="Tom", email="tom@example.com") 8 user3 = User(name="Steve", email="steve@example.com") 9 user3.friends = [user1, user2] 10 pprint(UserSchema().dump(user3)) 11 12 {'email': 'steve@example.com', 'friends': ['Mike', 'Tom'], 'name': 'Steve'} 13 14 data = { 15 "name": "Steve", 16 "email": "steve@example.com", 17 "friends": [ 18 "Tom", 19 "Mike" 20 ] 21 } 22 pprint(UserSchema().load(data)) 23 24 {'email': 'steve@example.com', 25 'friends': [{'name': 'Tom'}, {'name': 'Mike'}], 26 'name': 'Steve'}
也可以使用exclude参数来排除不要的字段,对于深度嵌套,同样可以使用“.”符号连接
- Partial Loading
反序列化时,嵌套的schemas也可以继承父类的partial参数
1 class UserSchemaStrict(Schema): 2 name = fields.String(required=True) 3 email = fields.Email() 4 created_at = fields.DateTime(required=True) 5 6 class BlogSchemaStrict(Schema): 7 title = fields.String(required=True) 8 author = fields.Nested(UserSchemaStrict, required=True) 9 10 schema = BlogSchemaStrict() 11 blog = {"title": "Something Completely Different", "author": {}} 12 result = schema.load(blog, partial=True) 13 pprint(result) 14 15 {'author': {}, 'title': 'Something Completely Different'}
同样可以通过“.”符号连接来指定partial字段的子集
1 author = {"name": "Monty", "email": "monty@example.com"} 2 blog = {"title": "Something Completely Different", "author": author} 3 result = schema.load(blog, partial=("title", "author.created_at")) 4 pprint(result) 5 6 {'author': {'email': 'monty@example.com', 'name': 'Monty'}, 7 'title': 'Something Completely Different'}
- Two-way Nesting
如果两个对象相互嵌套,则Nested可以传入类名的字符串形式,这允许在未定义该类时定义一个嵌套的schema类
1 class Author(object): 2 def __init__(self, name, email): 3 self.name = name 4 self.email = email 5 self.books = [] 6 7 class Book(object): 8 def __init__(self, title, author): 9 self.title = title 10 self.author = author 11 12 class AuthorSchema(Schema): 13 name = fields.Str() 14 email = fields.Email() 15 # Make sure to use the 'only' or 'exclude' params 16 # to avoid infinite recursion 17 books = fields.Nested('BookSchema', many=True, exclude=('author',)) 18 19 class Meta: 20 fields = ('name', 'email', 'books') 21 22 class BookSchema(Schema): 23 title = fields.Str() 24 author = fields.Nested(AuthorSchema, only=('name', 'email')) 25 26 class Meta: 27 fields = ('title', 'author') 28 29 author = Author(name="Mike", email="mike@yooh.com") 30 book = Book(title="This is a joke", author=author) 31 pprint(BookSchema().dump(book)) 32 33 {'author': {'email': 'mike@yooh.com', 'name': 'Mike'}, 34 'title': 'This is a joke'} 35 36 author.books = [book] 37 pprint(AuthorSchema().dump(author)) 38 39 {'books': [{'title': 'This is a joke'}], 40 'email': 'mike@yooh.com', 41 'name': 'Mike'} 42
- Nesting A Schema Within Itself
如果需要自引用,则Nested传入‘self’即可
1 class UserSchema(Schema): 2 name = fields.String() 3 email = fields.Email() 4 friends = fields.Nested("self", many=True) 5 # Use the 'exclude' argument to avoid infinite recursion 6 employer = fields.Nested("self", exclude=("employer",), default=None) 7 8 user = User("Steve", "steve@example.com") 9 user.friends.append(User("Mike", "mike@example.com")) 10 user.friends.append(User("Joe", "joe@example.com")) 11 user.employer = User("Dirk", "dirk@example.com") 12 result = UserSchema().dump(user) 13 pprint(result, indent=2) 14 15 # { 16 # "name": "Steve", 17 # "email": "steve@example.com", 18 # "friends": [ 19 # { 20 # "name": "Mike", 21 # "email": "mike@example.com", 22 # "friends": [], 23 # "employer": null 24 # }, 25 # { 26 # "name": "Joe", 27 # "email": "joe@example.com", 28 # "friends": [], 29 # "employer": null 30 # } 31 # ], 32 # "employer": { 33 # "name": "Dirk", 34 # "email": "dirk@example.com", 35 # "friends": [] 36 # } 37 # }