python 之 参数校验《一》 jsonschema模块
python 之 参数校验《二》 pydantic模块
python 之 参数校验《三》 marshmallow参数校验与序列化
sanic
、tortoise-orm
构建一个项目,由于sanic不具备自动序列化的功能,所以采用第三方的序列化模块from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
进行序列化pydantic
在 sanic 序列化觉得有点反人类,于是采用marshmallow
进行序列化pip install marshmallow
pip install marshmallow-enum
常规参数校验(字符串、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)
条件 | 存在 | 不存在 |
---|---|---|
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 |