Python类型提示
指定参数类型和返回类型
>>> def demo1(first_name: str, last_name: str) -> str:
return first_name.title() + " " + last_name.title()
>>> demo1("wang", "haha")
'Wang Haha'
>>>
带有子类型的类型
>>> from typing import List, Tuple, Dict
>>> def demo2(items: List[str]):
for item in items:
print(item)
>>> demo2(["ryan", "king", 24])
ryan
king
24
>>> def demo3(items: Tuple[int, str, int]):
for item in items:
print(item, type(item))
>>> demo3((3, "hello", 89))
3 <class 'int'>
hello <class 'str'>
89 <class 'int'>
>>> def demo4(info: Dict[str, str]):
for k, v in enumerate(info):
print(k, v)
>>> demo4({"name": "ryan", "age": 24})
0 name
1 age
类作为参数类型
>>> class Student:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
>>> def printName(stu: Student):
print(stu.getName())
>>> stu = Student("ryan")
>>> printName(stu)
ryan
Pydantic 模型
>>> from pydantic import BaseModel
>>> from typing import List
>>> from pydantic.error_wrappers import ValidationError
>>> class User(BaseModel):
id: int
name = "ryan"
hobby: List[str]
>>> data = {
"id": [123],
"name": "ryan",
"hobby": ["篮球", "皮球", "奶球"]
}
>>> try:
user = User(**data)
print(user)
print(user.id, user.name, user.hobby)
except ValidationError as e:
print(e)
1 validation error for User
id
value is not a valid integer (type=type_error.integer)
安装
pip install fastapi
ASGI
服务器
pip install uvicorn
HelloWorld
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
启动
uvicorn main:app --reload
接收PUT请求数据
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
交互式API文档
请求方法
@app.post()
@app.put()
@app.delete()
@app.options()
@app.head()
@app.patch()
@app.trace()
通常
POST: 创建数据
GET: 读取数据
PUT: 更新数据
DELETE: 删除数据
路径参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/index/{id}")
async def index(id):
return {"id": id}
http://127.0.0.1:8000/index/20
带有类型的路径参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/index/{id}")
async def index(id: int):
return {"id": id}
http://127.0.0.1:8000/index/25
执行顺序
因为路径操作是按顺序计算的,所以您需要确保/users/me
的路径是在/users/{user_id}
之前声明的, 不然路由永远匹配到/users/{user_id}
中
from fastapi import FastAPI
app = FastAPI()
@app.get('/users/me')
async def read_user_me():
return {'user_id': '10010'}
@app.get('/users/{user_id}')
async def read_user(user_id: str):
return {'user_id': user_id}
枚举参数
导入Enum
并创建一个继承自str
和Enum
的子类。
from fastapi import FastAPI
from enum import Enum
app = FastAPI()
# 通过从str中继承,API文档将能够知道值的类型必须是string,并且能够正确呈现。
class ModelName(str, Enum):
a = 'ryan'
b = 'king'
c = 'ryan'
@app.get('/model/{model_name}')
async def get_model(model_name: ModelName):
print('model_name', model_name)
print('key=', model_name.name)
print('val=', model_name.value)
return {model_name.name: model_name.value}
路径参数包含路径
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
http://127.0.0.1:8000/files/a/b/c/d/e/f/g
查询参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
print(skip)
print(limit)
http://127.0.0.1:8000/items/?skip=1&limit=3
可选参数
你可以声明可选的查询参数,通过设置它们的默认值为None
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str = None):
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
多个路径和查询参数
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
user_id: int, item_id: str, q: str = None, short: bool = False
):
item = {"item_id": item_id, "owner_id": user_id}
if q:
item.update({"q": q})
if not short:
item.update(
{"description": "This is an amazing item that has a long description"}
)
return item
Optional
from typing import Optional
limit: Optional[int] = None
from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_user_item(item_id: str, limit: Optional[int] = None):
item = {"item_id": item_id, "limit": limit}
return item
请求体
当你需要从一个客户端(简单来说是浏览器)发送数据给你的API,你发送的内容叫做请求体
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
使用模型
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
print(item)
print("json->", item.json())
print("dict->", item.dict())
print("Config->", item.Config)
print(item.dict().get("name"))
return item
请求体+路径参数
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item):
return {"item_id": item_id, **item.dict()}
请求体+路径参数+查询参数
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: str = None):
result = {"item_id": item_id, **item.dict()}
if q:
result.update({"q": q})
return result
功能参数将被识别如下:
- 如果在路径中也声明了该参数,它将用作路径参数。
- 如果参数是单数类型(例如
int
,float
,str
,bool
等),它将被解释为查询参数。 - 如果参数被声明为是一个Pydantic 模型,它将被解释为请求体。
查询参数和字符串的验证
额外的验证
限制查询参数长度
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/test")
async def test(item: str = Query(None, max_length=20, min_length=5)):
return item
当我们使用默认值None
替代Query(None)
时,Query的第一个参数具有定义默认值的相同目的。
q: str = Query(None)
等同于
q: str = None
匹配正则表达式参数
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/test")
async def test(item: str = Query(None, max_length=20, min_length=5, regex='^w.*a$')):
return item
http://127.0.0.1:8000/test?item=wanghaha
默认值
具有默认值也会使该参数成为可选参数。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/test")
async def test(item: str = Query('wanghaha', max_length=20, min_length=5, regex='^w.*a$')):
return item
当我们使用Query声明一个值时,你可以使用...
作为第一个参数, 它会让FastAPI知道这个参数是被需要的。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(..., min_length=3)):
print(q)
return q
查询参数列表/多个值
from fastapi import FastAPI, Query
from typing import List
app = FastAPI()
@app.get("/items/")
async def read_items(q: List[str] = Query(None)):
query_items = {"q": q}
return query_items
http://127.0.0.1:8000/items/?q=abc&q=defaazv&q=23
查询参数列表/多个值 默认值
from fastapi import FastAPI, Query
from typing import List
app = FastAPI()
@app.get("/items/")
async def read_items(q: List[str] = Query(["foo", "bar"])):
query_items = {"q": q}
return query_items
不指定list子元素类型
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list = Query(None)):
query_items = {"q": q}
return query_items
声明更多的原信息
添加title
, description
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items1/")
async def read_items(q: str = Query(None, title="Query string", min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
@app.get("/items2/")
async def read_items(
q: str = Query(
None,
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
参数别名
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(None, alias="item-query")):
print(q)
return q
http://127.0.0.1:8000/items/?item-query=hello
弃用参数
现在你再也不想看到这个参数。
您必须将其保留一段时间,因为有许多客户在使用它,但是您希望文档将其清楚地显示为已弃用。
然后将参数deprecated = True
传递给Query
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str = Query(
None,
deprecated=True,
)
):
print(q)
return q
http://127.0.0.1:8000/docs#/default/read_items_items__get
路径参数和数值验证
参数升序
Python不会对*做任何操作,但是它将知道以下所有参数都应称为关键字参数(键/值对),也称为kwargs。即使它们没有默认值。
from fastapi import FastAPI, Query, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*, item_id: int = Path(..., title="The ID of the item to get"), q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
数值验证: 大于等于
from fastapi import FastAPI, Query, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*, item_id: int = Path(..., title="The ID of the item to get", ge=1), q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
http://127.0.0.1:8000/items/3?q=hello
gt
: 大于le
: 小于等于lt
: 小于
Body多参数
from fastapi import FastAPI, Path
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
@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: str = None,
item: Item = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results
多个请求参数
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
class User(BaseModel):
username: str
full_name: str = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
results = {"item_id": item_id, "item": item, "user": user}
return results
请求体
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
}
}
Body指示FastAPI将其视为另一个主体密钥
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
class User(BaseModel):
username: str
full_name: str = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int, item: Item, user: User, importance: int = Body(...)
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
return results
期望请求体
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
},
"importance": 5
}
Body
还具有与Query
,Path
和其他稍后将看到的所有相同的额外验证和元数据参数。
嵌入单个主体参数
假设您只有Pydantic模型Item
中的单个body
参数。
默认情况下,FastAPI将直接期望其主体。
但是,如果您希望它期望一个带有关键item
的JSON,并且在其中包含模型内容,就像声明额外的主体参数时那样,则可以使用特殊的Body
参数embed
:
item: Item = Body(..., embed=True)
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: 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
期望请求主体
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
}
而不是
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
Body字段
声名模型属性
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: 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: 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
Field
的工作方式与Query
,Path
和Body
相同,它具有所有相同的参数,等等。
详细教程 实际上,接下来将看到
Query
,Path
和其他对象,它们创建了常见Param
类的子类的对象,而Param类本身是Pydantic的FieldInfo类的子类。 并且Pydantic的Field也返回FieldInfo的实例。Body
还直接返回FieldInfo子类的对象。还有其他一些您稍后会看到的是Body类的子类。 请记住,当您从fastapi导入Query,Path等时,这些实际上是返回特殊类的函数。提示 请注意,具有类型,默认值和
Field
的每个模型的属性如何与路径操作函数的参数具有相同的结构,用字段而不是Path
,Query
和Body
。
您可以使用Pydantic的Field
声明模型属性的额外验证和元数据。
您还可以使用extra关键字参数来传递其他JSON Schema
元数据。