marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库,简而言之,就是实现object -> dict, objects -> list, string -> dict 和 string -> list。
序列化:序列化的意思是将数据对象转化为可存储或可传输的数据类型 反序列化:将可存储或可传输的数据类型转化为数据对象
要进行序列化或反序列化,首先我们需要一个用来操作的object,这里我们先定义一个类:
import datetime
class User:
def __init__(self, name, age):
self.name = name
self.age = age
self.c_time = datetime.datetime.now()
通过 继承Schema
定义一个序列化类
class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
c_time = fields.DateTime()
生成一个对象,进行序列化
user = User("yxh", 20)
# 生成 schema 对象
schema = UserSchema()
'''
schema 对象序列化有两个方法
dump() 返回 dict 格式数据
dumps() 放回 json 格式数据
'''
print(schema.dump(user))
# {'c_time': '2023-02-27T10:48:10.481042', 'age': 20, 'name': 'yxh'}
print(schema.dumps(user))
# {"c_time": "2023-02-27T10:48:10.481042", "age": 20, "name": "yxh"}
res = {"name": "yxh", "c_time": "2023-02-27T10:51:06.713273", "age": 20}
print(schema.load(res))
# {'age': 20, 'name': 'yxh', 'c_time': datetime.datetime(2023, 2, 27, 10, 51, 6, 713273)}
对反序列化而言, 将传入的dict变成object更加有意义. 在Marshmallow中, dict -> object的方法需要自己实现, 然后在该方法前面加上一个装饰器post_load即可
class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
c_time = fields.DateTime()
@post_load
def make_user(self, data, **kwargs):
data.pop("c_time") # user 对象没有 c_time 字段
return User(**data)
res = '{"name": "yxh", "c_time": "2023-02-27T10:51:06.713273", "age": 20}'
item = schema.loads(res)
print(item) # <__main__.User object at 0x000002621BAB7588>
demo
UserSchema(only={"name", "age"})
参数可以 在实例化 sechema 对象时配置,也可以在使用序列化/反序列化时 传入
schema.dump(users,many=True)
参数名 | 作用 | 补充 |
---|---|---|
only | 指定序列化字段 | load_only/dump_only |
exclude | 抛弃未知字段 | |
many | 默认为False,批量序列化使用 | |
partial | 忽略字段,可指定忽略字段,也可设置为True,就忽略传入字段外的其他字段 | 通常在load()中使用,能够忽略 required = True 的字段 |
参数名 | 作用 | 补充 |
---|---|---|
required | 默认为False,定义为True 时必传 | |
validate | 指定校验方法 | |
error_messages | 设置错误信息 | 配合 required使用 |
attribute | 指定序列化时获取对象属性 | 默认是字段名 |
load_from | 指定反序列化时字典key 对应的对象属性 | 默认是字段名 |
data_key | attribute和load_from 结合体 | |
default | 指定默认值 | |
cls_or_instance | 用于可变类型嵌套 | |
allow_none | 序列化/反序列化期间True是否None应被视为有效值。 | 如果missing=None和allow_none未设置,则默认为True。否则,默认值为False。 |
metadata | 存储为元数据的额外参数 |
projects = fields.List(cls_or_instance=fields.Dict)
'''
特殊数据类型:
fields.Nested(nested, type, str, Callable[[], …) 类似于django中的外键序列化类型,用于使用额外的Schema序列化外键对象
fields.Method(serialize, deserialize, **kwargs) 一个采用Schema方法返回值的字段。类似于django序列化器中的函数字段,可以通过方法构造一个完整的字段返回,该字段可以不是模型中存在的。
fields.Function(serialize, Any], Callable[[Any, …) 接受函数返回值的字段。可将字段通过函数处理后将函数返回值作为该字段的值序列化返回。
'''
自定义反序列化校验函数函数
方案1:
def validate_name(name):
if len(name) <=2:
raise ValidationError("name长度必须大于2位")
if len(name) >= 6:
raise ValidationError("name长度不能大于6位")
class UserSchema(Schema):
name = fields.String(required=True, validate=validate_name)
age = fields.Integer()
c_time = fields.DateTime()
方案2:
from marshmallow import Schema, fields, validates
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer()
c_time = fields.DateTime()
@validates("name")
def validate_name(self, value):
if len(value) <= 2:
raise ValidationError("name长度必须大于2位")
if len(value) >= 6:
raise ValidationError("name长度不能大于6位")
validate.Email(*, error) 邮箱验证,error 表示可以替换内置的异常提示语,传入值为字符串。
validate.Equal(comparable, *, error) 相等验证,验证输入值是否等于给定值
validate.Length(min, max, *, equal, error) 长度验证,验证输入值的最大最小
validate.OneOf(choices, labels, *, error) 选项验证,验证输入值是否属于选项
validate.Range([min, max]) 范围验证
validate.Regexp(regex, bytes, Pattern][, flags]) 正则验证
validate.URL(*, relative, schemes, Set[str]] = None, …) 验证是否为URL
除了在生成 schema 对象是,传入参数,也可以在定义阶段通过 Meta 类来实现对属性的控制, 可定义类型常用 有 fileds 和 exclude 两个字段。
class Meta:
fields = ("id", "email", "date_created")
exclude = ("password", "secret_attribute")