FastAPI学习笔记(一)-2.初识Pydantic

零、普通Python类
 1 class myClass:
 2 
 3     def __init__(self, name, age, job):
 4         self.name = name
 5         self.age = age
 6         self.job = job
 7 
 8     def f(self):
 9         return 'hello world'
10 
11 myClass1 = myClass('invoker', 25, 'test')
12 
13 print(myClass1)
14 # <__main__.myClass object at 0x000001E09429B748>

 


一、使用Python的类型注释type hints 来进行数据校验 和 setting管理。
'''
@author:invoker
@project:fastapi202108
@file: pydantic_tutorial.py
@contact:invoker2021@126.com
@descript:
@Date:2021/8/4 18:05
@version: Python 3.7.8
'''

"""
一、使用Python的类型注释type hints 来进行数据校验 和 setting管理。
二、Pydantic可以在代码运行时提供类型提示,数据校验失败时提供友好的错误提示
三、定义输入应该如何在纯规范的Python代码中保存,并用Pydantic验证他。
"""

from pydantic import BaseModel
from datetime import datetime, date
from typing import List
from typing import Optional
print("\033[33;1m1. -----Pydantic的基本用法------------------\033[33;0m")


class User(BaseModel):
    id: int  # 没有给默认值则是必填字段,非int型可以自动转换成int型
    name: str = "John snow"  # 有默认值则是选填字段
    signup_ts: Optional[datetime] = None  # 使用Optional表示是选填字段,不填就是None
    friends: List[int] = []  # 列表中元素是int类型或则可以直接转换成int类型

external_data = {
    "id": '1',
    "signup_ts": "2021-08-04 18:00",
    "friends": [1, 2, "3"]  # "3"可以int("3")的
}

# python的解包,将字典的值分别赋值给对象中的属性
user = User(**external_data)

print(user)
# id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]
print(type(user))
# <class '__main__.User'>

# 每个字段单独输出
print(user.id, user.name, user.signup_ts, user.friends)
# 1 John snow 2021-08-04 18:00:00 [1, 2, 3]

# 时间字段按照原类型输出
print(repr(user.signup_ts))
# datetime.datetime(2021, 8, 4, 18, 0)

# 将该对象以字典方式输出
print(user.dict())
# {'id': 1, 'name': 'John snow', 'signup_ts': datetime.datetime(2021, 8, 4, 18, 0), 'friends': [1, 2, 3]}

 

 解包的解释:

 

 

 

二、Pydantic可以在代码运行时提供类型提示,数据校验失败时提供友好的错误提示
from pydantic import BaseModel, ValidationError
from datetime import datetime, date
from typing import List
from typing import Optionalprint("\033[33;1m1. -----Pydantic的基本用法------------------\033[33;0m")


class User(BaseModel):
    id: int  # 没有给默认值则是必填字段,非int型可以自动转换成int型
    name: str = "John snow"  # 有默认值则是选填字段
    signup_ts: Optional[datetime] = None  # 使用Optional表示是选填字段,不填就是None
    friends: List[int] = []  # 列表中元素是int类型或则可以直接转换成int类型



print("\033[33;1m2. -----------校验失败错误处理------------\033[33;0m")

try:
    User(id=1, signup_ts=datetime.today(), friends=[1, 2, 'not number'])
except ValidationError as e:
    print(e.json())

    # [
    #     {
    #         "loc": [
    #             "friends",
    #             2
    #         ],
    #         "msg": "value is not a valid integer",
    #         "type": "type_error.integer"
    #     }
    # ]

 

三、BaseModel类的属性和方法
from pydantic import BaseModel, ValidationError
from datetime import datetime, date
from typing import List
from typing import Optional
from pathlib import Path


class User(BaseModel):
    id: int  # 没有给默认值则是必填字段,非int型可以自动转换成int型
    name: str = "John snow"  # 有默认值则是选填字段
    signup_ts: Optional[datetime] = None  # 使用Optional表示是选填字段,不填就是None
    friends: List[int] = []  # 列表中元素是int类型或则可以直接转换成int类型

external_data = {
    "id": '1',
    "signup_ts": "2021-08-04 18:00",
    "friends": [1, 2, "3"]  # "3"可以int("3")的
}

print("\033[33;1m3. -----------BaseModel类的属性和方法------------\033[33;0m")
# 1.以字典格式输出
print(f'以字典格式输出:{user.dict()}')
# 结果:{'id': 1, 'name': 'John snow', 'signup_ts': datetime.datetime(2021, 8, 4, 18, 0), 'friends': [1, 2, 3]}

print(f'type:{type(user.dict())}')  # dict
# type:# <class 'dict'>

# 2.以json格式输出
print(f'以json格式输出:{user.json()}')
# 以json格式输出:{"id": 1, "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}

print(f'type:{type(user.json())}')  # str
# type:# <class 'str'>

# 3.浅拷贝
print(f'浅拷贝:{user.copy()}')
# 浅拷贝:id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]

print(f'type:{type(user.copy())}')  # User
# <class '__main__.User'>

# 4.解析数据的方法
# 4.1
print(f'解析数据的方法1:{User.parse_obj(obj=external_data)}')
# 解析数据的方法1:id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]

print(f'type{type(User.parse_obj(obj=external_data))}')  # User
# <class '__main__.User'>

# 4.2
print(f'解析数据方法2:{User(**external_data)}')
# 解析数据方法2:id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]

print(f'type:{type(User(**external_data))}')  # User
# <class '__main__.User'>

# 4.3
print(f'解析数据的方法3:解析规范的原生str数据') # 原生数据就是字符串数据且是有规律的key,value键值对的数据
print(User.parse_raw('{"id": 1, "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}'))
# id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]

# 4.4 解析文件
print(f'解析数据的方法4:解析文件')
path = Path('pydantic_tutorial.json') # 用到 pathlib 的 path,path是一个对象
path.write_text('{"id": 1, "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}')
print(User.parse_file(path))
# id=1 name='John snow' signup_ts=datetime.datetime(2021, 8, 4, 18, 0) friends=[1, 2, 3]
print(type(User.parse_file(path)))
# <class '__main__.User'>

# 5 数据格式
print(user.schema())
# {'title': 'User', 'type': 'object', 'properties': {'id': {'title': 'Id', 'type': 'integer'}, 'name': {'title': 'Name', 'default': 'John snow', 'type': 'string'}, 'signup_ts': {'title': 'Signup Ts', 'type': 'string', 'format': 'date-time'}, 'friends': {'title': 'Friends', 'default': [], 'type': 'array', 'items': {'type': 'integer'}}}, 'required': ['id']}

print(user.schema_json())
# {"title": "User", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "default": "John snow", "type": "string"}, "signup_ts": {"title": "Signup Ts", "type": "string", "format": "date-time"}, "friends": {"title": "Friends", "default": [], "type": "array", "items": {"type": "integer"}}}, "required": ["id"]}

# 6 construct 不校验数据创建BaseModel对象实例,此方法只在特殊场景使用。
user_data = {"id": 'error', "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}
print(user.construct(**user_data))
# name='John snow' signup_ts='2021-08-04T18:00:00' friends=[1, 2, 3] id='error'
print(type(user.construct(**user_data)))
# <class '__main__.User'>

# 7 字段顺序
print(User.__fields__.keys())  # 只要在定义模型类时,所有字段都注明类型,字段顺序就不会乱
# dict_keys(['id', 'name', 'signup_ts', 'friends'])

 

 

四、递归模型(嵌套:一个模型内调用另一个模型)

应用场景不太清楚???

 

from pydantic import BaseModel
from typing import Optional
from typing import List



print("\033[33;1m4. -----------递归模型(嵌套:在一个模型内调用另一个模型)------------\033[33;0m")


class Sound(BaseModel):
    sound: str


class Dog(BaseModel):
    birthday: date
    weight2: Optional[float] = None
    sound: List[Sound]

dogs = Dog(birthday=date.today(),  weight2=2.22, sound=[{"sound": "wang!"}, {"sound": "o!"}])
print(dogs.dict())

 

 如果传入值是sound1,则会报错

  1 '''
  2 @author:invoker
  3 @project:fastapi202108
  4 @file: pydantic_tutorial.py
  5 @contact:invoker2021@126.com
  6 @descript:
  7 @Date:2021/8/4 18:05
  8 @version: Python 3.7.8
  9 '''
 10 
 11 """
 12 一、使用Python的类型注释type hints 来进行数据校验 和 setting管理。
 13 二、Pydantic可以在代码运行时提供类型提示,数据校验失败时提供友好的错误提示
 14 三、定义输入应该如何在纯规范的Python代码中保存,并用Pydantic验证他。
 15 """
 16 
 17 from pydantic import BaseModel, ValidationError
 18 from datetime import datetime, date
 19 from typing import List
 20 from typing import Optional
 21 from pathlib import Path
 22 
 23 print("\033[33;1m1. -----Pydantic的基本用法------------------\033[33;0m")
 24 
 25 
 26 class User(BaseModel):
 27     id: int  # 没有给默认值则是必填字段,非int型可以转换成int型
 28     name: str = "John snow"  # 有默认值则是选填字段
 29     signup_ts: Optional[datetime] = None  # 使用Optional表示是选填字段,不填就是None
 30     friends: List[int] = []  # 列表中元素是int类型或则可以直接转换成int类型
 31 
 32 
 33 external_data = {
 34     "id": '1',
 35     "signup_ts": "2021-08-04 18:00",
 36     "friends": [1, 2, "3"]  # "3"可以int("3")的
 37 }
 38 
 39 # python的解包,将字典的值分别赋值给对象中的属性
 40 user = User(**external_data)
 41 # 每个字段单独输出
 42 print(user.id, user.name, user.signup_ts, user.friends)
 43 # 时间字段按照原类型输出
 44 print(repr(user.signup_ts))
 45 # 将该对象以字典方式输出
 46 print(user.dict())
 47 
 48 print("\033[33;1m2. -----------校验失败错误处理------------\033[33;0m")
 49 
 50 try:
 51     User(id=1, signup_ts=datetime.today(), friends=[1, 2, 'not number'])
 52 except ValidationError as e:
 53     print(e.json())
 54 
 55 print("\033[33;1m3. -----------BaseModel类的属性和方法------------\033[33;0m")
 56 # 1.以字典格式输出
 57 print(f'以字典格式输出:{user.dict()}')
 58 print(f'type:{type(user.dict())}')  # dict
 59 # 2.以json格式输出
 60 print(f'以json格式输出:{user.json()}')
 61 print(f'type:{type(user.json())}')  # str
 62 # 3.浅拷贝
 63 print(f'浅拷贝:{user.copy()}')
 64 print(f'type:{type(user.copy())}')  # User
 65 # 4.解析数据的方法
 66 # 4.1
 67 print(f'解析数据的方法1:{User.parse_obj(obj=external_data)}')
 68 print(f'type{type(User.parse_obj(obj=external_data))}')  # User
 69 # 4.2
 70 print(f'解析数据方法2:{User(**external_data)}')
 71 print(f'type:{type(User(**external_data))}')  # User
 72 # 4.3
 73 print(f'解析数据的方法3:解析规范的原生str数据')
 74 print(User.parse_raw('{"id": 1, "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}'))
 75 # 4.4 解析文件
 76 print(f'解析数据的方法4:解析文件')
 77 path = Path('pydantic_tutorial.json')
 78 path.write_text('{"id": 1, "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}')
 79 print(User.parse_file(path))
 80 
 81 # 5 数据格式
 82 print(user.schema())
 83 print(user.schema_json())
 84 
 85 # 6 construct 不校验数据创建BaseModel对象实例,此方法只在特殊场景使用。
 86 user_data = {"id": 'error', "name": "John snow", "signup_ts": "2021-08-04T18:00:00", "friends": [1, 2, 3]}
 87 print(user.construct(**user_data))
 88 print(type(user.construct(**user_data)))
 89 
 90 # 7 字段顺序
 91 print(User.__fields__.keys())  # 只要在定义模型类时,所有字段都注明类型,字段顺序就不会乱
 92 
 93 print("\033[33;1m4. -----------递归模型(嵌套:在一个模型内调用另一个模型)------------\033[33;0m")
 94 
 95 
 96 class Sound(BaseModel):
 97     sound: str
 98 
 99 
100 class Dog(BaseModel):
101     birthday: date
102     weight2: Optional[float] = None
103     sound: List[Sound]
104 
105 dogs = Dog(birthday=date.today(),  weight2=2.22, sound=[{"sound1": "wang!"}, {"sound": "o!"}])
106 print(dogs.dict())
View Code

 

 

 五、创建ORM模型

 1 '''
 2 @author:invoker
 3 @project:fastapi202108
 4 @file: orm.py
 5 @contact:invoker2021@126.com
 6 @descript:
 7 @Date:2021/8/5 10:21
 8 @version: Python 3.7.8
 9 '''
10 # SQLAlchemy==1.3.22
# SQL alchemy: sql炼金术
# sqlalchemy.dialects.方言,即可以选择mysql,oracle,postgresql不同的数据库
11 from sqlalchemy import Column, Integer, String 12 from sqlalchemy.dialects.postgresql import ARRAY 13 from sqlalchemy.ext.declarative import declarative_base
# declarative_base()是一个工厂函数,它为声明类定义构建了一个基类(在示例中分配给Base变量).不懂
14 # pydantic==1.7.3 15 from pydantic import BaseModel, constr,ValidationError 16 # python自带类型 17 from typing import List 18 19 print("\033[33;1m1. -----------------ORM模型:从类实例创建ORM对象的模型------------------\033[33;0m") 20 # 声明式编程 21 Base = declarative_base() 22 23 # ORM:对象关系映射(Object Relational Mapping,简称ORM 24 # ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象与关系数据库相互映射 25 26 # Column中的String(20)感觉并没有起到约束的作用 27 class CompanyOrm(Base): 28 __tablename__ = "companies" 29 id = Column(Integer, primary_key=True, nullable=False) 30 public_key = Column(String(20), index=True, nullable=False, unique=True) 31 name = Column(String(63), unique=True) 32 domains = Column(ARRAY(String(255))) 33 34 35 # BaseModel中的constr起到约束验证作用。 36 class CompanyMode(BaseModel): 37 id: int 38 public_key: constr(max_length=20) 39 name: constr(max_length=63) 40 domains: List[constr(max_length=255)] 41 42 class Config: 43 orm_mode = True 44 45 try: 46 co_orm = CompanyOrm( 47 id=123, 48 public_key='foobar', 49 name='testing', 50 domains=['invoker.com', 'test.com'] 51 ) 52 except ValidationError as e: 53 print(e.json()) 54 #所有以上将不符合规则的value存入co_orm并没有报错。 55 56 print(co_orm) 57 print(co_orm.public_key) 58 try: 59 print(CompanyMode.from_orm(co_orm)) 60 # id = 123 61 # public_key = 'foobar' 62 # name = 'testing' 63 # domains = ['invoker.com', 'test.com'] 64 except ValidationError as e: 65 print(e.json()) 66 # 而使用BaseModel时,会校验value的有效性 67 print(type(CompanyMode.from_orm(co_orm))) 68 # <class '__main__.CompanyMode'>

 

 六、Pydantic中涉及到的类型:

https://pydantic-docs.helpmanual.io/usage/types/

 

 

 

 

 

 

 

posted @ 2021-08-05 11:00  kaer_invoker  阅读(346)  评论(0)    收藏  举报