1、phonenumbers的使用

在Python中,phonenumbers 库是一个非常流行的库,用于解析、格式化、存储和验证国际电话号码。而 pydantic 是一个数据解析和验证库,它基于Python类型提示,使得数据验证变得简单且类型安全。将 phonenumberspydantic 结合使用,可以在模型验证中包括电话号码的验证。

下面是如何在 pydantic 模型中使用 phonenumbers 来验证电话号码的一个示例。

首先,你需要安装必要的库(如果你还没有安装它们的话):

1
pip install phonenumbers pydantic

然后,可以创建一个自定义的验证器,该验证器使用 phonenumbers 来检查电话号码是否有效,并将其集成到 pydantic 模型中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from typing import Optional  
from pydantic import BaseModel, ValidationError, validator
from phonenumbers import parse, PhoneNumberFormat, UnknownTimeZoneError, NumberParseException

class PhoneNumber(BaseModel):
e164: Optional[str] = None
international: Optional[str] = None
national: Optional[str] = None
raw_input: str

@validator('raw_input', pre=True)
def validate_phone_number(cls, v):
try:
parsed_number = parse(v, None) # 第二个参数是区域代码,这里使用None尝试自动解析
if not parsed_number.is_valid():
raise ValueError("Phone number is not valid.")

# 存储不同的电话号码格式
cls.e164 = parsed_number.format_e164()
cls.international = parsed_number.format_international()
cls.national = parsed_number.format_national()

# 验证器不应直接返回数据,因为它只是预处理,这里返回原始值
return v

except (NumberParseException, UnknownTimeZoneError) as e:
raise ValueError(f"Invalid phone number: {e}")

# 使用模型
try:
phone = PhoneNumber(raw_input="+12025550145")
print(phone.json())
except ValidationError as e:
print(e)

在这个例子中,PhoneNumber 类是一个 pydantic 模型,它接受一个 raw_input 字段作为电话号码的原始输入。使用 @validator 装饰器,我们定义了一个预处理验证器 validate_phone_number,它使用 phonenumbers.parse 来解析电话号码,并检查其是否有效。如果电话号码有效,则根据 phonenumbers 提供的格式函数生成并存储 e164internationalnational 格式的电话号码。

注意,由于 @validator 装饰器上的 pre=True 参数,该验证器会在字段值被赋值到模型实例之前运行。此外,验证器函数本身不直接返回要赋给字段的值(因为我们在类级别上设置了其他字段),而是返回原始输入值 v,以便它可以被正常处理并赋值给 raw_input 字段。

最后,我们尝试实例化 PhoneNumber 模型并传入一个有效的电话号码,然后打印出模型的JSON表示。如果传入无效的电话号码,则会捕获并打印出 ValidationError 异常。

2、在 Pydantic 模型中使用PhoneNumber

pydantic_extra_types 是一个扩展 pydantic 的类型系统的开发包,包括添加对特定数据类型(如电话号码)的支持。在使用前,需要安装:

1
pip install pydantic phonenumbers pydantic_extra_types

完成安装后,既可以在模型中定义PhoneNumber类型的字段。

1
2
3
4
5
6
from pydantic import BaseModel  
from pydantic_extra_types import PhoneNumber

class User(BaseModel):
name: str
phone_number: PhoneNumber

3、定义一个国内电话号码的PhoneNumber

1
2
3
4
5
class ChinesePhoneNumber(PhoneNumber):
"""中国电话号码数据类型."""

default_region_code = "CN"
phone_format = "E164"