目录
嗯,今天的博主讲的挺细
pyCharm自动调整代码格式 ctrl+alt+L
pydantic库
pydantic是一个用来用来执行数据校验的 Python 库。
可以在代码运行时提供类型提示,数据校验失败时提供友好的错误提示
pyCharm中可以安装pydantic插件
基本用法
先引用
from pydantic import BaseModel
定义数据模型
class User(BaseModel): id: int #必填字段 name: str = "Bob" #有默认值,选填字段 time: Optional[datetime] = None # 时间字段可以不填,不填就是None friends: List[int] = [] # 列表中的元素要是int类型,或者可以直接转换成int类型
数据实例化
external_data = { "id": "123", "time": "2022-2-15 11:42", "friends":[1,2,"3"] }
输出
user = User(**external_data) print(user.id, user.friends) # 实例化后调用属性 print(user.dict()) #字典形式 print(user.json()) #json格式
校验失败处理
try: # 这个friend数据类型是int,不能是字符串,有个错误,放在try中 User(id=1, time=datetime.today(), friends=[1, 2, "not number"]) except ValidationError as e: print(e.json())
递归模型
class Sound(BaseModel): sound: str class Dog(BaseModel): birthday: date weight: float = Optional[None] sound: List[Sound] #Dog中嵌套这Sound,递归模型就是指一个嵌套一个 #实例化 dogs = Dog(birthday=date.today(), weight=6.66, sound=[{"sound": "wang wang ~"},{"sound":"ying ying ~"}]) print(dogs.dict())
可选类型 option
from typing import Optional
name: str = "John" #有默认值,选填字段 time: Optional[datetime] = None # 时间字段可以不填,不填就是None
这两种写法实质上一样
FastAPI的请求参数和验证
异步
from fastapi import FastAPI from pydantic import BaseModel from typing import Optional #实例化应用 app = FastAPI() #这里不一定是app,名字随意 # 数据模型 class CityInfo(BaseModel): province: str country: str is_affected: Optional[bool] = None # hello_world方法用@app装饰器get方法,这样hello_world方法就变成了接口 @app.get('/') def hello_world(): return {"hello":"world"} #异步 @app.put('/city/{city}') async def city(city: str, city_info: CityInfo): return {'city':city, 'country': city_info.country, 'is_affected': city_info.is_affected}
交互文档的使用
文档地址127.0.0.1:8000/docs
数据的解析、验证
from fastapi import APIRouter from fastapi import Path # 专门校验路径参数的类 from enum import Enum # 枚举类型 app03 = APIRouter()
1.路径参数和数字验证
# 这个是没有参数 @app03.get('/path/parameters') def path_params01(): return {"message": "This is a message"} # 这个有参数,要注意{parameters}和parameters要一致 这两个接口路径一样,一定要注意前后顺序,函数的顺序就是路由的顺序 @app03.get('/path/{parameters}') def path_params01(parameters: str): return {"message": parameters}
2.枚举类型验证
class CityName(str, Enum): Beijing = "Beijing China" Shanghai = "Shanghai China" @app03.get('/enum/{city}') # 枚举类型的参数是可供选择的 async def latest(city: CityName): if city == CityName.Shanghai: return {"city_name": city, "confired": 1492, "death": 6} if city == CityName.Beijing: return {"city_name": city, "confired": 971, "death": 4} return {"city_name": city, "latest": "unknow"}
3. 文件路径验证
# 通过path parameters传递文件路径 # 因为http://127.0.0.1:8000/chapter03/files/ 这个路径本来就有很多斜杠,如果传递的参数是文件路径的话就容易出错,所以就要加上:path @app03.get('/files/{file_path:path}') def filepath(file_path: str): return f" The file path is {file_path} "
4.关于长度和正则表达式的验证,常用
用到Path类
@app03.get('/path_params/{num}') # Path类 可以校验,要求num参数是int类型,必填(...),添加标题,添加描述,大于等于1,小于等于10 def path_params_validate( num: int = Path(..., title="your number", description="描述 ", ge=1, le=10) ): return num
5.查询参数
@app03.get('/query') # 给了默认值就是选填的参数,没给默认值就是必填参数,也就是这两个都是选填的 def page_limit(page: int=1, limit: Optional[int]=None): if limit: return {"page": page, "limit": limit} return {"page": page}
6.布尔类型转换
# bool类型转换,yes on 1 True true都是true 其他都是false 或者报错 @app03.get('/query/bool/conversion') def type_conversion(param: bool = False): return param
7.字符串的验证
@app03.get('/query/validation') def query_v( # 查询,必填,最小长度是3,最大长度是16,regex是正则,以a开头 value: str = Query(..., min_length=3, max_length=16, regex="^a"), # 多个查询参数的列表, default默认值,alias起一个别名 values: List[str] =Query(default=["v1", "v2"], alias="bieming") ): return value,values
8.请求体和字段
class CityInfo(BaseModel): name: str = Field(..., example="Beijing") # example是注解的左右,不会被验证 country: str country_code: str = None #给一个默认值,选填 country_population: int = Field(default=800, title="人口数量", description="国家人口的数量", ge=800) #子类 实例会在文档中显示 class Config: schema_extra = { "example": { "name":"Shanghai", "country": "China", "country_code": "CN", "country_population": 1400000000 } } @app03.post("/request_body/city") def city_info(city: CityInfo): print(city.name, city.country) #输出到控制台 return city.dict()
9.多参数混合使用
@app03.put('/requeset_body/city/{name}') def mix_city_info( # 函数 name: str, # 路径参数 city01: CityInfo, # 符合CityInfo格式 city02: CityInfo, #Body可以定义多个的 请求体参数 confirmed: int = Query(ge=0, description="确诊数", default=0), # 查询参数 death: int = Query(ge=0, description="死亡数", default=0) ): if name == "Shanghai": return {"Shanghai": {"confirmed": confirmed, "death": death}} return city02.dict(), city01.dict()
10.数据格式嵌套的请求体
class Data(BaseModel): city: List[CityInfo] = None # 这里是定义数据格式嵌套的请求体 date: date #额外的数据类型 confirmed: int = Field(ge=0, description="确诊数", default=0) death: int = Field(ge=0, description="死亡数", default=0) recovered: int = Field(ge=0, description="痊愈数", default=0) @app03.put("/request_body/nested") def nested(data: Data): return data
11. cookie参数
@app03.get("/cookie") # 目前效果只能用Postman测试 def cookie(cookie_id: Optional[str] = Cookie(None)): # 定义Cookie参数需要使用Cookie类,否则就是查询参数 return {"cookie_id": cookie_id}
12. Header参数
@app03.get("/header") def header(user_agent: Optional[str] = Header(None, convert_underscores=True), x_token: List[str] = Header(None)): """ 有些HTTP代理和服务器是不允许在请求头中带有下划线的,所以Header提供convert_underscores属性让设置 :param user_agent: convert_underscores=True 会把 user_agent 变成 user-agent :param x_token: x_token是包含多个值的列表 :return: """ return {"User-Agent": user_agent, "x_token": x_token}
这个注释会显示在文档中