python 之 参数校验《二》 pydantic模块

澹台志诚
2023-12-01

python 之 参数校验《一》 jsonschema模块
python 之 参数校验《二》 pydantic模块
python 之 参数校验《三》 marshmallow参数校验与序列化

一、背景

在api接口中,需要验证一些参数;如django、flask 有些组件支持参数的校验;
但是适用场景具有针对性,定制化程度过高,扩展性不强;
如果想自定义一些参数,则可已选用这个模块pydantic

二、官方文档

pip install pydantic

三、案例

  • 案例一: 验证如下

    验证不能为空
    验证默认值
    验证布尔类型
    验证验证启用别名
    验证时间模块
    验证非必传Optional
    验证数组类型 [1, 2, '3']
    验证多个类型其中之一即可 Union[int, str]
    自定义验证@validator
    
    from enum import Enum, IntEnum
    from datetime import datetime, date
    
    from typing import List, Union
    from typing import Optional
    from pydantic import BaseModel, Field, ValidationError, validator
    
    class UserModel(BaseModel):
        user_id: int                            # 必传项, 可以为int 可以str类型int
        username: str                           # 必传项, 可以为int 可以str类型int
        gender: str                             # 必传值, 此处为自定义校验
        active: bool = False                    # bool 类型 默认值 False
        school = "吹灯大学"                      # 添加新字段修改值
        address: str = Field(alias="addr")      # 将传入addr输出为address
    
        create_time: datetime
        signup_ts: Optional[datetime] = None
        merge: Union[int, str]                  # 数据可以允许多种数据类型  zhangsan, 123 均可
        age: Optional[int]                      # 非必传参数, 默认值为None
        tag: List[int] = []                     # 传入数组类型
    
        @validator("gender")
        def check_gender(cls, v):
            if v not in ["male", "female"]:
                raise ValueError("sex is wrong!!!")
            return v
    
    data =  {
        "user_id": 12345,
        "username": 1456789,
        "age": 18,
        "gender": "male",
        "addr": "北京潘家园",
        'aa': False,
        'tag': [1, '2', 3],
        "create_time": "2022-09-12 03:04:05",
        "merge": "123a"
    }
    
    try:
        user = UserModel(**data)
        print(user.dict())
        print(user.json())
    except ValidationError as e:
        print(e)
     
    {'user_id': 12345, 'username': '1456789', 'gender': 'male', 'active': False, 'address': '北京潘家园', 'create_time': datetime.datetime(2022, 9, 12, 3, 4, 5), 'merge': '123a', 'age': 18, 'tag': [1, 2, 3], 'school': '吹灯大学'}
    {"user_id": 12345, "username": "1456789", "gender": "male", "active": false, "address": "\u5317\u4eac\u6f58\u5bb6\u56ed", "create_time": "2022-09-12T03:04:05", "merge": "123a", "age": 18, "tag": [1, 2, 3], "school": "\u5439\u706f\u5927\u5b66"}
    
    注: 如int传入的str类型的int则转成int
        如int传入float 类型的int则保留整数
    
  • 案例二: 枚举类型校验

    class GenderEnum(IntEnum):
        male = 0
        female = 1
    
    
    class ShirtEnum(str, Enum):
        S = "Small"
        M = "Medium"
        L = "Large"
    
    
    class ConfigModel(BaseModel):
        user_id: int
        username: str
        gender: GenderEnum
        shirt: ShirtEnum = ShirtEnum.S  # 设置默认
    
    data =  {
        "user_id": 12345,
        "username": 1456789,
        "book": 2,
        "shirt": "Small"
        "test": "zhangsan"
    }
    
    user = ConfigModel(**data)
    print(user.dict())         
    print(user.gender.value)  # 输出值   0
    print(user.shirt.value)   # 输出值   Small
    
    {'user_id': 12345, 'username': '1456789', 'gender': <GenderEnum.male: 0>, 'shirt': <ShirtEnum.S: 'Small'>}
    
  • 案例三: 高级复杂检查 --> 数组-与对象的嵌套应用

    class SchoolModel(BaseModel):
        sch_id: int = 100
        school: str
    
    
    class UserModel(BaseModel):
        user_id: int                            # 必传项, 可以为int 可以str类型int
        username: str                           # 必传项, 可以为int 可以str类型int
        age: int = 18                           # 默认值 18
        gender: GenderEnum
    
    
    class UserListModel(BaseModel):
    
        tag: List[int] = []
        school: SchoolModel
        users: List[UserModel]
    
    
    data = {
        "tag": [1, 3, '5', 7],
        "school": {"sch_id": 12345, "school": "上海中学"},
        "users": [
            {"user_id": 12345, "username": "zhangsan", "gender": 1, "book": 2},
            {"user_id": 12354, "username": "lisi", "gender": 1, "book": 2},
            {"user_id": 12543, "username": "wanger", "gender":1, "book": 2},
        ]
    }
    
    
    
    user = UserListModel(**data)
    print(user.dict())         
    print(user.school.sch_id)   #  输出值   上海中学
    print(user.users) 
    
    {'tag': [1, 3, 5, 7], 'school': {'sch_id': 12345, 'school': '上海中学'}, 'users': [{'user_id': 12345, 'username': 'zhangsan', 'age': 18, 'gender': <GenderEnum.female: 1>}, {'user_id': 12354, 'username': 'lisi', 'age': 18, 'gender': <GenderEnum.female: 1>}, {'user_id': 12543, 'username': 'wanger', 'age': 18, 'gender': <GenderEnum.female: 1>}]}
    
    [UserModel(user_id=12345, username='zhangsan', age=18, gender=<GenderEnum.female: 1>), UserModel(user_id=12354, username='lisi', age=18, gender=<GenderEnum.female: 1>), UserModel(user_id=12543, username='wanger', age=18, gender=<GenderEnum.female: 1>)]
    
    
  • 案例四: 高级复杂检查 --> Field应用
    用于为模型架构或复杂验证提供有关字段的额外信息。一些参数仅适用于数字字段(intfloatDecimal),有些仅适用于str

    :param default  factory:可调用,当此字段需要默认值时将调用它
        如果同时设置了default和default  factory,则会引发错误。
    :param alias:字段的公共名称
    :param title:可以是架构中使用的任何字符串
    :param multiple of:仅适用于数字,要求字段为“的倍数”。这个架构将有一个“multipleOf”验证关键字
    :param regex:仅适用于字符串,要求字段与正则表达式匹配模式字符串。架构将有一个“pattern”验证关键字
    :param**extra:任何其他关键字参数都将按原样添加到架构中
    
    如果default未定义且default\U factory未为None:
    raise VALUERROR(不能同时指定default和default工厂)
    
    default: Any = Undefined,
    default_factory: Optional[NoArgAnyCallable] = None,
    alias: str = None,
    title: str = None,
    description: str = None,
    const: bool = None,
    gt: float = None,
    ge: float = None,
    lt: float = None,
    le: float = None,
    multiple_of: float = None,
    min_items: int = None,
    max_items: int = None,
    min_length: int = None,
    max_length: int = None,
    regex: str = None,
    **extra: Any,
    
    data2 = {"username": '12345', "weight": 77, "age": 33, "height": '2.16'}
    
    class UserModel(BaseModel):
        username: str = Field(default=None, description='姓名', min_length=3, max_length=16)
        weight: int = Field(default=0,  description='体重', gt=60, lt=90)  # gt 大于  lt 小于
        age: int = Field(default=18,  description='年龄', ge=18, le=50)    # ge 大于等于  le 小于等于
        height: float = Field(default=1.75, description='身高', ge=1.67, le=2.22)
        school: str = "996"
    
    user = UserModel(**data2)
    print(user.dict())
    
参考
  • 官方文档 https://pydantic-docs.helpmanual.io/
  • https://blog.csdn.net/swinfans/article/details/89629641
  • https://blog.csdn.net/codename_cys/article/details/107675748
 类似资料: