python 之 参数校验《一》 jsonschema模块
python 之 参数校验《二》 pydantic模块
python 之 参数校验《三》 marshmallow参数校验与序列化
一、背景
- 用
sanic、tortoise-orm构建一个项目,由于sanic不具备自动序列化的功能,所以采用第三方的序列化模块 - 采用fastapi 自带序列化输出,切能用
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator进行序列化 - 上面
pydantic在 sanic 序列化觉得有点反人类,于是采用marshmallow进行序列化
二、安装与介绍
- 2.1 marshmallow的安装
pip install marshmallow pip install marshmallow-enum - 2.2 字段及属性介绍
三、简单示例
-
常规参数校验(字符串、int、列表、字典、邮箱、时间、日期、常量、默认值、自定义校验规则等)
class ScoreSchema(Schema): English = fields.Integer(required=True, validate=validate.Range(min=0, max=100)) Chinese = fields.Integer(required=True, validate=validate.Range(min=0, max=100)) creature = fields.Integer(required=True, validate=validate.Range(min=0, max=100)) class PersonSchema(Schema): username = fields.String(required=True, validate=lambda s:len(s) < 6) # required gender = fields.Str(required=True, validate=validate.OneOf(['male', 'female', 'other'])) # 枚举类型 age = fields.Integer(required=True) # 自定义验证器方式 height = fields.Integer(validate=validate.Range(min=100, max=120)) email = fields.Email() # 非必传 location = fields.String(required=True, validate=validate.Length(min=4, max=16)) activate = fields.Boolean(default=True) country = fields.Constant('China') score = fields.Nested(ScoreSchema, required=True) lucky_num = fields.List(fields.Integer(), required=True) like = fields.List(fields.String(), required=True) birthdate = fields.Date(required=True, format='%Y-%m-%d', error_messages={'invalid': 'Invalid date format. Expected YYYY-MM-DD.'}) created_at = fields.DateTime(format='%Y-%m-%d %H:%M:%S', required=True, error_messages={'required': 'Created at is required.', 'invalid': 'Invalid datetime format. Expected YYYY-MM-DD HH:MM:SS.'}) declaration = fields.Str(dump_default="Hello World") # 仅在dump生成 declaration2 = fields.Str(load_default="Hello World") # 仅在dump生成 @validates('age') # 自定义验证器方式 def validate_age(self, value): if value < 18: raise ValidationError("the age is young!") @validates_schema def validate_gender_age(self, data, **kwargs): if data['gender'] == 'male' and data['age'] > 35: # raise ValidationError({'age': "people age 35 no support"}) # 自定义 raise ValidationError("people male age 35 no support") try: input_data = { "username": "zhangsan", "age": '18', "location": "location", 'gender': 'male', 'activate': True, 'birthdate': '1993-02-03', 'created_at': '1993-02-03 00:00:00', 'like': ["成龙", "科比", "罗大佑"], 'lucky_num': ["22",33, 55], "score": { "English": 66, "Chinese": 88, "creature": 34 } } schema = PersonSchema() person = schema.load(input_data) print("通过1", person) result = schema.dump(person) print("通过2", result) except ValidationError as err: print("错误", err) print("错误", err.valid_data) -
校验列表中带有字典功能
input_data = [ {"English": 66,"Chinese": 88,"creature": 34}, {"English": 66,"Chinese": 88,"creature": 34} ] errors = ScoreSchema(many=True).validate(input_data) if errors: print(errors) else: print("Validation succeeded!") -
枚举的校验、以及教研时生成常量
class MyEnum(Enum): QUICK = "quick" STANDARD = "standard" DEEP = "deep" class MySchema(Schema): mode = fields.String(validate=validate.OneOf([mode.value for mode in MyEnum])) my_enum = fields.Str(required=True, validate=lambda x: x in [e.value for e in MyEnum]) param = fields.Dict() data = { 'mode': 'quick','my_enum': 'standard', 'param': {} } result = MySchema().dump(data) print(result)
四、fields字段的default、missing、dump_default、load_default 区别(此处有坑,留心留意)
| 条件 | 存在 | 不存在 |
|---|---|---|
| default | load 如果存在仅做验证, | 不存不验证 |
| dump 如果存在不验证, 只输出默认值 | 不存在输出默认值 | |
| missing | load 如果存在则验证 | 不存在则输出默认值 |
| dump 如果存在则验证 | 不存在则无输出 | |
| dump_default | load 如果存在则验证 | 不存在则无输出 |
| dump 如果存在不验证, 输出为字符串 | 不存在则输出默认 | |
| load_default | load 如果存在则验证 | 不存在则输出默认值 |
| dump 如果存在不验证, 输出为字符串 | 不存在则无输出 |
default: 字段的默认值。如果输入数据中没有该字段,将使用默认值。默认值可以是常量、函数、类等。如果是函数,则该函数将在初始化时被调用并返回默认值。missing:当输入数据缺少该字段时使用的默认值。与 default 参数不同,该值仅在输入数据中缺少该字段时使用,并不影响输出数据。dump_default:当字段的值为默认值时,使用的输出值。如果没有指定该参数,则默认输出该字段的实际值。可以用于压缩输出数据,避免输出大量相同的默认值。load_default: 当字段的值为默认值时,使用的输入值。用于在输入数据中填充缺失的默认值。如果没有指定该参数,则默认使用 missing 参数的值。
from marshmallow import Schema, fields
class PersonSchema(Schema):
name = fields.String()
age = fields.Integer(missing=18)
activate = fields.Boolean(default=True) # json load 仅做验证 不会输出
motto = fields.Str(dump_default="Hello World") # 仅在dump生成
declaration = fields.Str(load_default="爱我中华") # 仅在dump生成
data = {"name": "Alice", "age": 20, "activate":True, "motto": "PHP is best", "declaration": "Life is short. I use python" }# "Life is short. I use python"
person = PersonSchema().load(data)
print(person)
result = PersonSchema().dump(data)
print(result)
综上所述,
1. default 和 missing 都是用于指定默认值的,
但 default 用于指定输入数据中缺失时使用的默认值,
而 missing 用于指定输出数据中缺失时使用的默认值。
2. dump_default 和 load_default 则分别用于指定输出数据中字段值为默认值时使用的输出值,
以及在输入数据中缺少该字段时使用的默认值。
五、字段类型及属性
| 字段类型 | 注释 | 属性 | 备注 |
|---|---|---|---|
| String | 字符串 | allow_none | 是否允许为 None |
| as_string | 是否转化为字符串 | ||
| Integer | 整数 | allow_none | 是否允许为 None |
| error | 校验错误信息 | ||
| Float | 浮点数 | allow_nan | 是否允许 NaN 值 |
| allow_infinity | 是否允许无穷大值 | ||
| Decimal | 十进制数 | places | 小数保留位数 |
| rounding | 小数舍入方式 | ||
| allow_nan | 是否允许 NaN 值 | ||
| allow_infinity | 是否允许无穷大值 | ||
| as_string | 是否转化为字符串 | ||
| coerce | 是否允许强制转化 | ||
| quantize | 是否允许量化 | ||
| context | 上下文信息 | ||
| Boolean | 布尔值 | truthy | 布尔值为 True 的值 |
| falsy | 布尔值为 False 的值 falsy=[‘no’, ‘false’, ‘0’] | ||
| DateTime | 时间/日期 | format | 时间/日期格式 |
| Time | 时间 | format | 时间格式 |
| Date | 日期 | format | 日期格式 |
| TimeDelta | 时间差 | error | 校验错误信息 |
| List | 列表 | cls_or_instance | 列表元素类型 |
| Tuple | 元组 | cls_or_instance | 元组元素类型 |
| Dict | 字典 | cls_or_instance | 字典元素类型 |
| keys | 字典键的类型 | ||
| values | 字典值的类型 | ||
| Union | 多个字段类型 | field_names | 字段类型名称列表 |
| fields | 字段类型列表 | ||
| Function | 函数 | deserialize | 反序列化方法 |
| serialize | 序列化方法 | ||
| validate | 校验方法 | ||
| Nested | 嵌套 | nested | 嵌套 schema |
| exclude | 排除字段列表 | ||
| only | 仅包含字段列表 | ||
| many | 是否为多个对象 | ||
| context |
546

被折叠的 条评论
为什么被折叠?



