请求体
from typing import Optional
import uvicorn
from fastapi import Body, FastAPI, Path
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
class User(BaseModel):
username: str
full_name: Optional[str] = None
# 混合Path、Query 请求体参数
# 多个请求体参数 item user
# importance 默认情况 单一值被解释为查询参数, body同样有数据校验机制
# embed 将原本的请求体嵌入到一个键中
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
q: Optional[str] = None,
item: Optional[Item]=Body(..., embed=True),
# item: Optional[Item] = None,
user: User,
importance: int = Body(..., gt=0)
):
results = {"item_id": item_id, 'user': user, 'importance': importance}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
请求体-字段 feild
from typing import Optional
import uvicorn
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = Field(
None, title="The description of the item", max_length=300
)
price: float = Field(..., gt=0, description="The price must be greater than zero")
tax: Optional[float] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
results = {"item_id": item_id, "item": item}
return results
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
请求体-嵌套模型
from typing import List, Optional, Set, Dict
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
# url: str
name: str
url: HttpUrl
# list -> List -> Set
# 嵌套数据模型
# str -> HttpUrl
# 一组子模型 List[Image]
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
# tags: list = [] #
# tags: List[int] = []
tags: Set[str] = set()
image: Optional[Image] = None
images: Optional[List[Image]] = None
# 多层嵌套
class Offer(BaseModel):
name: str
description: Optional[str] = None
price: float
items: List[Item]
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
@app.post('/offers/')
async def create_offer(offer: Offer):
return offer
# 返回列表[] 而非{}
@app.post('/images/multiple')
async def create_multiple_images(images: List[Image]):
return images
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
print(weights)
return weights
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
添加额外的信息
from typing import Optional
import uvicorn
from fastapi import FastAPI, Body
from pydantic import BaseModel, Field
app = FastAPI()
# 添加额外信息
# 法1:使用Config和schema_extra
# 法2:Field、body等 example
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
class Config:
schema_extra = {
"example": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
}
class Item1(BaseModel):
name: str = Field(..., example="Foo")
description: Optional[str] = Field(None, example="A very nice Item")
price: float = Field(..., example=35.4)
tax: Optional[float] = Field(None, example=3.2)
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, item1: Item1, item2: Item = Body(
...,
example={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
)):
results = {"item_id": item_id, "item": item, "item1": item1, 'item2': item2}
return results
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
其余数据类型
# 基础数据类型 int float str bool
# UUID、datetime.datetime datetime.date datetime.time datetime.timedelta、 frozenset、 bytes、 Decimal
from datetime import datetime, time, timedelta
from typing import Optional
from uuid import UUID
from fastapi import Body, FastAPI
import uvicorn
app = FastAPI()
# https://1024tools.com/uuid
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
start_datetime: Optional[datetime] = Body(None),
end_datetime: Optional[datetime] = Body(None),
repeat_at: Optional[time] = Body(None),
process_after: Optional[timedelta] = Body(None),
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
return {
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
"repeat_at": repeat_at,
"process_after": process_after,
"start_process": start_process,
"duration": duration,
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
cookie header
要想获取cookie、header 浏览器中需要有相应的属性值
from typing import Optional,List
from fastapi import Cookie, FastAPI, Header
import uvicorn
app = FastAPI()
@app.get("/items/")
async def read_items(ads_id: Optional[str] = Cookie(None)):
return {"ads_id": ads_id}
@app.get("/items1/")
async def read_items(user_agent: Optional[str] = Header(None)):
return {"User-Agent": user_agent}
@app.get("/items2/")
async def read_items(
strange_header: Optional[str] = Header(None, convert_underscores=False)
):
return {"strange_header": strange_header}
@app.get("/items3/")
async def read_items(x_token: Optional[List[str]] = Header(None)):
return {"X-Token values": x_token}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
响应模型
response_model参数
mac 无法安装pydantic[email],执行pip install email-validator
和 pip install typing_extensions即可
response_model_exclude_unset等参数,对返回结果进行限制
from typing import List, Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
import uvicorn
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
tags: List[str] = []
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Optional[str] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
# Don't do this in production!
# @app.post("/user/", response_model=UserIn)
# async def create_user(user: UserIn):
# return user
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
return item
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}",
response_model=Item,
response_model_exclude_unset=True) # 忽略默认值
async def read_item(item_id: str):
return items[item_id]
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public",
response_model=Item,
response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
return items[item_id]
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
额外的模型
尽量减少代码的重复,封装公共模块
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
import uvicorn
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
# class UserIn(BaseModel):
# username: str
#
# password: str
#
# email: EmailStr
# full_name: Optional[str] = None
class UserIn(UserBase):
password: str
# class UserOut(BaseModel):
# username: str
# email: EmailStr
# full_name: Optional[str] = None
class UserOut(UserBase):
pass
# class UserInDB(BaseModel):
# username: str
#
# hashed_password: str
#
# email: EmailStr
# full_name: Optional[str] = None
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
多个数据模型进行切换
from typing import Union, List, Dict
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type = "car"
class PlaneItem(BaseItem):
type = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem]) # union
async def read_item(item_id: str):
return items[item_id]
@app.get("/items/", response_model=List[Item]) # 模型列表
async def read_items():
return items
@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
响应码
from fastapi import FastAPI, status
import uvicorn
app = FastAPI()
# 200 成功、 300 重定向 400 客户端错误
# @app.post("/items/", status_code=201)
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
return {"name": name}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
form
from fastapi import FastAPI, Form
import uvicorn
app = FastAPI()
@app.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):
return {"username": username}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
文件
from typing import List
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
import uvicorn
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
contents = await file.read()
return {"filename": file.filename, 'contents': contents}
@app.post("/files1/")
async def create_files(files: List[bytes] = File(...)):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles1/")
async def create_upload_files(files: List[UploadFile] = File(...)):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
"""
return HTMLResponse(content=content)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
form 与file
from fastapi import FastAPI, File, Form, UploadFile
import uvicorn
app = FastAPI()
@app.post("/files/")
async def create_file(
file: bytes = File(...), fileb: UploadFile = File(...), token: str = Form(...)
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")