Marshmallow
本文主要对marshmallow的文档进行整理,并记录在学习Marshmallow文档时碰到的一些问题和解决方法
原文链接:https://marshmallow.readthedocs.io/en/stable/quickstart.html
Todo:
- 添加validation相关的内容
- 将内容按照接口重新排序
- 添加ordering, implicit field creation, nested schemas, custom field, extending schemas相关的内容
- 纠正翻译
正文
1. 声明schema
首先创建一个简单的User类,声明了构造方法和覆写__repr__方法用于打印对象
import datetime as dt
class User:
def __init__(self, name, email):
self.name = name
self.email = email
self.created_at = dt.datetime.now()
def __repr__(self):
return "<User(name={self.name!r})>".format(self=self)
然后创建一个继承Schema的UserSchema类,里面生成name,email,create_at变量,映射属性名到Field对象
from marshmallow import Schema, fields
class UserSchema(Schema):
name = fields.Str()
email = fields.Email()
created_at = fields.DateTime()
也可以使用Schema.from_dict()通过传入dict来创建Schema。比较有用的应用场景是在运行中生成Schema
UserSchema = Schema.from_dict(
{
"name": fields.Str(),
"email": fields.Email(),
"created_at": fields.DateTime()}
)
2. 序列化对象 – dumping
使用dump、dumps可以序列化对象。dump返回格式化好的数据,dumps返回json String
from pprint import pprint
user = User(name="Monty", email="monty@python.org")
schema = UserSchema()
result = schema.dump(user)
pprint(result)
# {"name": "Monty",
# "email": "monty@python.org",
# "created_at": "2014-08-17T14:54:16.049594+00:00"}
2.1 过滤输出 – only
使用only,传入tuple或者数组,可以指定输出的fields
summary_schema = UserSchema(only=("name", "email"))
summary_schema.dump(user)
# {"name": "Monty", "email": "monty@python.org"}
3. 反序列化 – load
dump反过来就是load,load会验证并反序列化一个字典 为 应用级别的数据结构。直接使用load,会将dict中的value转换成对应field定义的对象。
from pprint import pprint
user_data = {
"created_at": "2014-08-11T05:26:03.869245",
"email": "ken@yahoo.com",
"name": "Ken",
}
schema = UserSchema()
result = schema.load(user_data)
pprint(result)
# {'name': 'Ken',
# 'email': 'ken@yahoo.com',
# 'created_at': datetime.datetime(2014, 8, 11, 5, 26, 3, 869245)},
如果想将dict整体转换为对象,需要在Schema 中声明一个方法并用@post_load装饰。下面的例子就是将dict转换成了User对象
from marshmallow import Schema, fields, post_load
class UserSchema(Schema):
name = fields.Str()
email = fields.Email()
created_at = fields.DateTime()
@post_load
def make_user(self, data, **kwargs):
return User(**data)
user_data = {"name": "Ronnie", "email": "ronnie@stones.com"}
schema = UserSchema()
result = schema.load(user_data)
print(result) # => <User(name='Ronnie')>
4. 处理对象集合(多个对象)
在创建Schema的时候,传入(many=True),让Schema可以处理多个对象
user1 = User(name="Mick", email="mick@stones.com")
user2 = User(name="Keith", email="keith@stones.com")
users = [user1, user2]
schema = UserSchema(many=True)
result = schema.dump(users) # OR UserSchema().dump(users, many=True)
pprint(result)
# [{'name': u'Mick',
# 'email': u'mick@stones.com',
# 'created_at': '2014-08-17T14:58:57.600623+00:00'}
# {'name': u'Keith',
# 'email': u'keith@stones.com',
# 'created_at': '2014-08-17T14:58:57.600623+00:00'}]
5. 必须值 required
在field中传入required,说明这个值不可或缺。如果缺少值的话,会报错。可以通过 error_messages={“required”: {“message”: “City required”, “code”: 400}} 来自定义错误返回的消息和错误码
from pprint import pprint
from marshmallow import Schema, fields, ValidationError
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer(required=True, error_messages={"required": "Age is required."})
city = fields.String(
required=True,
error_messages={"required": {"message": "City required", "code": 400}},
)
email = fields.Email()
try:
result = UserSchema().load({"email": "foo@bar.com"})
except ValidationError as err:
pprint(err.messages)
# {'age': ['Age is required.'],
# 'city': {'code': 400, 'message': 'City required'},
# 'name': ['Missing data for required field.']}
当一个schema用在不同地方时,required的值不同的话,通过load时传入partial=(“需要忽略的”),可以忽略required要求的字段值。
直接传入partial=True可以忽略所有的required
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer(required=True)
result = UserSchema().load({"age": 42}, partial=("name",)) #跳过name
# OR UserSchema(partial=('name',)).load({'age': 42})
print(result) # => {'age': 42}
result = UserSchema().load({"age": 42}, partial=True) #跳过所有
# OR UserSchema(partial=True).load({'age': 42})
print(result) # => {'age': 42}
5. 声明默认值
通过load_default和dump_default,声明默认值
class UserSchema(Schema):
id = fields.UUID(load_default=uuid.uuid1)
birthdate = fields.DateTime(dump_default=dt.datetime(2017, 9, 29))
UserSchema().load({})
# {'id': UUID('337d946c-32cd-11e8-b475-0022192ed31b')}
UserSchema().dump({})
# {'birthdate': '2017-09-29T00:00:00+00:00'}
6. 只读和只写
在fields.str()中传入load_only=True是只写,dump_only=True是只读
class UserSchema(Schema):
name = fields.Str()
# password is "write-only"
password = fields.Str(load_only=True)
# created_at is "read-only"
created_at = fields.DateTime(dump_only=True)
7. 自定义key
如果输入和输出的变量名不同,需要使用data_key=""自定义key的名称
class UserSchema(Schema):
name = fields.String()
email = fields.Email(data_key="emailAddress")
s = UserSchema()
data = {"name": "Mike", "email": "foo@bar.com"}
result = s.dump(data)
# {'name': u'Mike',
# 'emailAddress': 'foo@bar.com'}
data = {"name": "Mike", "emailAddress": "foo@bar.com"}
result = s.load(data)
# {'name': u'Mike',
# 'email': 'foo@bar.com'}