FastAPI -- 第一弹

Hello World

经典的 Hello World

安装

bash 复制代码
pip install fastapi
pip install "uvicorn[standard]"

main.py

python 复制代码
from typing import Union

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: Union[str, None] = None):
    return {"item_id": item_id, "q": q}

运行

bash 复制代码
uvicorn main:app --reload

交互式 API 文档

http://127.0.0.1:8000/doc (由 Swagger UI生成)

或者

http://127.0.0.1:8000/redoc (由 ReDoc 生成)

参数

路径参数

python 复制代码
from fastapi import FastAPI

app = FastAPI()

# http://127.0.0.1:8000/items/foo
@app.get("/items/{item_id}")
async def read_item(item_id):

	# return {"item_id": "foo"}
    return {"item_id": item_id}
声明路径参数的类型
python 复制代码
from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):	#  通过类型注解,声明 item_id 为 int 类型
    return {"item_id": item_id}
数据转换
python 复制代码
from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: int):	#  通过类型注解,声明 item_id 为 int 类型
    return {"item_id": item_id}

运行上面的示例代码,并访问 http://127.0.0.1:8000/items/3,

返回的响应如下:
{"item_id": 3}

顺序很重要

url /users/me/users/{user_id} , 路径操作是按顺序依次运行的,因此,一定要在/users/{user_id}之前声明 /users/me

python 复制代码
from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

否则,/users/{user_id} 将匹配 /users/me,FastAPI 会认为正在接收值为 "me" 的 user_id 参数

查询参数(问号参数)

声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数。

参数优先级: 路径参数> 查询参数

默认值 | 可选参数,必填参数
python 复制代码
from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]

# skip: int = 0, limit: int = 10
# skip 和 limit 都设置了默认值
# 
# 访问 http://127.0.0.1:8000/items/
# 访问 http://127.0.0.1:8000/items/?skip=0&limit=10
# 访问 http://127.0.0.1:8000/items/?skip=20
# 上面的三种访问方式是等效的,
# 所以设置默认值之后的参数等效于可选参数
#
# 同理 将其他类型的字段设置为其对应的**默认值**或者**None**,就可以使该字段变为 **可选字段**
# 例如: int = 0, str = "",  bool = False
#       int|None = None , str|None = None,  bool|None = None
# 建议使用 
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]

必选参数

不设置默认值的参数,就是必选参数

使用 Query 作为默认值
python 复制代码
from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
使用 Query 添加更多校验
python 复制代码
from typing import Union

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None, 
        min_length=3, 
        max_length=50,
        alias="An alternative name for the parameter field.",
        title="Human-readable title",
        description="Human-readable description",
        deprecated="Mark this parameter field as deprecated.",
        pattern="RegEx pattern for strings.",
        ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

请求体

创建数据模型&声明请求体
python 复制代码
from fastapi import FastAPI
from pydantic import BaseModel

# 创建数据模型
class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):	
# item: Item, 声明 item Item 类型,
# 由于 Item 属于 BaseModel类型,所以会被识别为请求体 
    return item
参数识别规则

函数参数按如下规则进行识别:

  • 路径中声明了相同参数的参数,是路径参数
  • 类型是(int、float、str、bool 等)单类型的参数,是查询参数
  • 类型是 Pydantic 模型的参数,是请求体
校验请求体字段
python 复制代码
from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str

	# 通过 Field 为字段 description 增加更多信息 或者校验
	# TODO: 
	# 		from pydantic import Field
	# 		from fastapiimport Query,Path,Body
    description: str | None = Field(
        default=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 = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    results = {"item_id": item_id, "item": item}
    return results
多个请求体参数&请求体中的单一值
python 复制代码
from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


class User(BaseModel):
    username: str
    full_name: str | None = None


@app.put("/items/{item_id}")
async def update_item(
	# 多个请求体参数
    item_id: int, item: Item, 
    user: User, 
    
    # 通过 Annotated[int, Body()] 将 声明为请求体参数,
    # 否则根据参数识别规则,将被识别为 查询参数
    importance: Annotated[int, Body()] 
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results

期望请求体示例

json 复制代码
{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}

模型

嵌入单个请求体

python 复制代码
from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, 
                      
                      # 通过 Annotated[Item, Body(embed=True)]
                      # 将 item 作为 key 嵌入到请求体中
                      item: Annotated[Item, Body(embed=True)],
                      ):
    results = {"item_id": item_id, "item": item}
    return results

期望请求体示例

json 复制代码
{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    }
}

嵌套模型 & List

python 复制代码
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
	
	# 通过 list 将 Image 作为 元素嵌入到 Item中
    images: list[Image] | None = None
    
	# 同理,通过 list 将 str作为 元素嵌入到 Item 中
    # images: List[str] | None = None
    # images: List[int] | None = None
    
	# 同理,将 Image 直接 嵌入到 Item 中
    # images: Image | None = None



@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

期望请求体示例

json 复制代码
{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": [
        "rock",
        "metal",
        "bar"
    ],
    "images": [
        {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        },
        {
            "url": "http://example.com/dave.jpg",
            "name": "The Baz"
        }
    ]
}

多层嵌套模型

python 复制代码
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
    images: list[Image] | None = None


class Offer(BaseModel):
    name: str
    description: str | None = None
    price: float
    items: list[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):

    return from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: set[str] = set()
    images: list[Image] | None = None


class Offer(BaseModel):
    name: str
    description: str | None = None
    price: float
    items: list[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):
	# 多层嵌套
	# offer -> Item         -> Image
	#       -> list[Item]
	#                       -> list[Image]
    return offer

为模型添加额外信息

python 复制代码
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }
    }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

到此结  DragonFangQy 2024.07.11

相关推荐
阡之尘埃1 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
丕羽4 小时前
【Pytorch】基本语法
人工智能·pytorch·python
bryant_meng5 小时前
【python】Distribution
开发语言·python·分布函数·常用分布
m0_594526306 小时前
Python批量合并多个PDF
java·python·pdf
工业互联网专业6 小时前
Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现
vue.js·hadoop·python·flask·毕业设计·源码·课程设计
钱钱钱端6 小时前
【压力测试】如何确定系统最大并发用户数?
自动化测试·软件测试·python·职场和发展·压力测试·postman
慕卿扬6 小时前
基于python的机器学习(二)—— 使用Scikit-learn库
笔记·python·学习·机器学习·scikit-learn
Json____7 小时前
python的安装环境Miniconda(Conda 命令管理依赖配置)
开发语言·python·conda·miniconda
小袁在上班7 小时前
Python 单元测试中的 Mocking 与 Stubbing:提高测试效率的关键技术
python·单元测试·log4j
白狐欧莱雅7 小时前
使用python中的pygame简单实现飞机大战游戏
经验分享·python·游戏·pygame