pydantic做参数校验

定义一个统一的schema类对提交的业务参数进行格式和数据约束非常有必要,
下面使用 pydantic 来封装此工具;

import logging
from pydantic import BaseModel, ValidationError, root_validator

class PydanticValidationError(Exception):
    def __init__(self, msg):
        self.message = msg


class BaseSchema(BaseModel):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    class Config:
        anystr_strip_whitespace = True
        use_enum_values = True
        arbitrary_types_allowed = True

    @root_validator(pre=True)
    def _pre_empty_data(cls, values: dict):
        """将空字符串或null字符串转换为None"""
        for k, v in values.items():
            if v == "" or v == "null":
                values[k] = None
        return values

    @classmethod
    def data_validation(cls, data):
        """参数校验,并自定义返回信息"""
        # TODO 这里并不一定是全部的,后面如果碰到其他的,再添加
        try:
            res = cls.parse_obj(data)
            errs = []
        except ValidationError as e:
            res = None
            errs = e.errors()
        for err in errs:
            logging.exception(err)
            fields = list(err["loc"])
            field = fields[0]
            field_info = cls.__fields__.get(field).field_info  # type: ignore
            type_info = err["type"].split(".")
            fields[0] = field_info.title if field_info.title else field
            title = ">>".join([str(tmp) for tmp in fields])
            if len(type_info) == 2:
                if type_info[0] == "type_error" and type_info[1] == "enum":
                    raise PydanticValidationError(f"{title}数据错误,请传指定可选值")
                if type_info[0] == "type_error":
                    raise PydanticValidationError(f"{title}数据类型错误,需要是{type_info[1]}类型")
                if type_info[0] == "value_error" and type_info[1] == "missing":
                    raise PydanticValidationError(f"{title}不能为空")
                if type_info[0] == "value_error" and type_info[1] == "const":
                    raise PydanticValidationError(f"{title}数据错误,请传指定值")
                if type_info[0] == "value_error" and type_info[1] == "ipv4address":
                    raise PydanticValidationError(f"{title}数据错误,需要是ipv4地址")
            if len(type_info) == 3:
                if type_info[2] == "not_gt":
                    raise PydanticValidationError(f"{title}的数值必须大于{field_info.gt}")
                if type_info[2] == "not_lt":
                    raise PydanticValidationError(f"{title}的数值必须小于{field_info.lt}")
                if type_info[2] == "not_ge":
                    raise PydanticValidationError(f"{title}的数值必须大于或等于{field_info.ge}")
                if type_info[2] == "not_le":
                    raise PydanticValidationError(f"{title}的数值必须小于或等于{field_info.le}")
                if type_info[2] == "min_length":
                    raise PydanticValidationError(f"{title}的最小字符长度为{field_info.min_length}")
                if type_info[2] == "max_length":
                    raise PydanticValidationError(f"{title}的最大字符长度为{field_info.max_length}")
                if type_info[2] == "min_items":
                    raise PydanticValidationError(f"{title}中的最少需要{field_info.min_items}个元素")
                if type_info[2] == "max_items":
                    raise PydanticValidationError(f"{title}中的最多只能{field_info.min_items}个元素")
                if type_info[1] == "none" and type_info[2] == "not_allowed":
                    raise PydanticValidationError(f"{title}不能为空")
            raise PydanticValidationError(f"{title}参数错误")
        return res

定义一个schema来接收参数, 它继承BaseSchema

class VictimOrgSchema(BaseSchema):
    title: str = Field(max_length=50, title="组织名称", description="组织名称")
    street: Optional[str] = Field(max_length=255, title="街道具体地址", description="街道具体地址", default="")
    latitude: str = Field(description="经度")
    longitude: str = Field(description="纬度")
    first_id: Optional[int] = Field(description="一级总指挥id")
    second_id: Optional[int] = Field(description="二级总指挥id")
    third_id: Optional[int] = Field(description="三级总指挥id")
    department_id: Optional[int] = Field(title="行业性质",description="行业性质")
    org_nature: int = Field(title="组织性质",description="组织性质")
    contacts: Optional[str] = Field(max_length=255, title="联系人", description="联系人")
    phone: Optional[str] = Field(max_length=11, title="联系电话", description="联系电话")
    logo: Union[FileStorage, str, None] = Field(description="logo")
    province: int = Field(description="省份code")
    city: int = Field(description="城市code")
    team_target: int = Field(description="是否靶标单位", default=0)

view里面进行参数校验

args = dict(request.form) if request.form else {}
data_obj = VictimOrgSchema.data_validation(args)

posted @ 2024-07-31 16:17  干炸小黄鱼  阅读(3)  评论(0编辑  收藏  举报