什么是数据校验?

在实际的开发过程当中,我们往往会面临很多需要数据对接的情况,这时候一个函数可能需要处理一个或者多个数据参数,也就是说函数的参数面临着多且不确定性,参数本身不确定性还伴随着在传递过程当中是否符合规范的问题。以python函数为例,以下是随意写法和标准写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 随意
def max(a,b):
if a>b:
return a
elif a<b:
return b
return 0

# 建议的标准写法
def max(a:int=0,
b:int=0)->int:
"""
这里描述函数的功能
:param a: 参数描述
:param b: 参数描述
:returns: 返回描述
:raises keyError: 可能的错误捕获描述
"""
if a>b:
return a
elif a<b:
return b
return 0

除此之外还有def exmaple2(required_arg, *arg, **kwarg):这样的写法,这些写法都是在极力是的python的函数与参数信息更加明确,让调用函数的时候能够清楚的知道函数的作用。
由于需求的复杂逐步增加,因此数据接口从原先的单纯的写法升级为固定规则,需要一些额外的协助手段才能够帮助使用者规范接口,pydantic库的出现极大程度的解决了这些问题。

pydantic库的基础

基本使用方法

schema基本定义方法

pydantic库的数据定义方式是通过BaseModel类来进行定义的,所有基于pydantic的数据类型本质上都是一个BaseModel类,它最基本的使用方式如下:

1
2
3
4
from pydantic import BaseModel

class Person(BaseModel):
name: str

基本的schema实例化方法

调用时,我们只需要对其进行实例化即可,实例化方法有以下几种:

1
2
3
4
5
6
7
8
9
10
11
12
#直接传值
p = Person(name="Tom")
print(p.json()) # {"name": "Tom"}

# 通过字典传入
p = {"name": "Tom"}
p = Person(**p)
print(p.json()) # {"name": "Tom"}

# 通过其他的实例化对象传入
p2 = Person.copy(p)
print(p2.json()) # {"name": "Tom"}

当传入值错误的时候,pydantic就会抛出报错,例如:Person(person="Tom") ;pydantic会抛出异常;另一方面,如果传入值多于定义值时,BaseModel也会自动对其进行过滤。如:

1
2
p = Person(name="Tom", gender="man", age=24)
print(p.json()) # {"name": "Tom"}

可以看到,额外的参数gender与age都被自动过滤了。通过这种方式,数据的传递将会更为安全,但是,同样的,这也要求我们在前期的schema定义中必须要尽可能地定义完全。此外,pydantic在数据传输时会直接进行数据类型转换,因此,如果数据传输格式错误,但是可以通过转换变换为正确的数据类型是,数据传输也可以成功,例如:

1
2
p = Person(name=123)
print(p.json()) # {"name": "123"}

pydantic基本数据类型

下面,我们来看一下pydantic中的一些常用的基本类型。

1
2
3
4
5
6
7
8
9
10
11
12
from pydantic import BaseModel
from typing import Dict, List, Sequence, Set, Tuple

class Demo(BaseModel):
a: int # 整型
b: float # 浮点型
c: str # 字符串
d: bool # 布尔型
e: List[int] # 整型列表
f: Dict[str, int] # 字典型,key为str,value为int
g: Set[int] # 集合
h: Tuple[str, int] # 元组

以上都是基础的使用,在实际使用过程当中,可以参考官方文档,会给出更加详细的写法。

使用

数据校验常常使用在需要被绑定在一起的复杂数据之上,也用于数据传递的校验,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User(BaseModel):
id: int # 无默认值,必填字段
name = 'John Doe' # 有默认值,选填字段
signup_ts: Optional[datetime] = None # 选填字段
friends: List[int] = [] # 列表中的元素是int类型或者是可以转换成int类型的其他类型

error_data = {
'id': 'a123',
'signup_ts': '2017-06-01 12:22',
'friends': [1, '2', '3']
}

try:
User(**error_data)
except ValidationError as e:
print(e.json())

这个案例展示了数据在接受错误参数的时候进行的自动校验,这样在数据十分复杂的情况下的时候就能够及时的判定数据是否传输异常而不是去一个个检查数据的状态。

总结

这是一个规范性的问题,不需要太多总结,反而需要足够的代码经验去填补这方面经验的缺失。个人也注意到这个问题,因此写下一篇超短的文章记录一下。
最后附上官网地址,只有全英文的:https://pydantic-docs.helpmanual.io/