fastapi_No.11_依赖项(1)

依赖的介绍

依赖项可以是一个函数,也可以是一个类。通过在路径操作函数中引入依赖项,可以达到先调用依赖项,并将依赖项调用的结果作为路径操作函数的输入。
下面通过一个示例来引出依赖项。
当多个路径操作函数中都具有相同的处理逻辑时,可以将共同的处理逻辑提取出来,作为依赖项。然后将这个依赖项引入各个路径操作函数中。这样就可以复用代码,将代码重复最小化。
在这里插入图片描述
依赖项通常使用在如下场景:

  • 共享业务逻辑(复用相同的代码逻辑)
  • 共享数据库连接
  • 实现安全、验证、角色权限等

函数依赖

当依赖项是一个函数的时候,此时依赖项就是一个函数依赖。
常见和使用函数依赖主要有以下步骤:
步骤1:创建依赖函数
示例中创建一个返回字典的函数。

# 步骤1:创建依赖函数,和定义函数没有区别
async def common_parameters(
    q:Union[str,None] = None,
    skip:int = 0,
    limit:int = 100
):
    return {
        "q":q,
        "skip":skip,
        "limit":limit
    }

步骤2:在路径操作函数中使用依赖项

# 步骤2:在路径操作函数中使用依赖函数
# 要使用依赖项,需要引入fastapi中的Depends函数
@app.get("/items")
async def read_items(commons:dict = Depends(common_parameters)):
    return commons

完整代码:

from typing import Union
from fastapi import Depends,FastAPI
app = FastAPI()
# 步骤1:创建依赖函数,和定义函数没有区别
async def common_parameters(
    q:Union[str,None] = None,
    skip:int = 0,
    limit:int = 100
):
    return {
        "q":q,
        "skip":skip,
        "limit":limit
    }

# 步骤2:在路径操作函数中使用依赖函数
# 要使用依赖项,需要引入fastapi中的Depends函数
@app.get("/items")
async def read_items(commons:dict = Depends(common_parameters)):
    return commons
@app.get("/users")
async def read_users(commons:dict = Depends(common_parameters)):
    return commons
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app="main:app",host="127.0.0.1",port=8080,reload=True)

这个示例中路径操作函数执行过程:

  1. 执行common_parameters函数,并得到返回值commons
  2. 路径操作函数将commons作为输入,执行其函数体中的逻辑

通过这个执行过程可以看出依赖项,在路径操作函数执行前,进行了一些逻辑处理。
或者可以说路径操作函数的结果依赖于依赖项的执行结果。

有一点需要新手注意:依赖项的输入参数是路径操作函数的一部分!以查询参数方式输入
本示例验证结果:
在这里插入图片描述

类依赖

在fastapi中不仅仅函数可以作为依赖项,类也可以作为依赖项。这里仅修改函数依赖中的代码进行说明。
依赖也分两步使用:
步骤1:创建公共类

# 步骤1:创建公共类
class CommonQueryParams:
    def __init__(self,q:Union[str,None]=None,skip:int = 0,limit:int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit

步骤2:路径操作函数中引用公共类

# 步骤2:在路径操作函数中引入公共类
@app.get("/item")
async def read_item(common:CommonQueryParams=Depends(CommonQueryParams)):
    return jsonable_encoder(common)

完整代码如下:

from typing import Union

from fastapi import Depends,FastAPI
from fastapi.encoders import jsonable_encoder

app = FastAPI()

# 步骤1:创建公共类
class CommonQueryParams:
    def __init__(self,q:Union[str,None]=None,skip:int = 0,limit:int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit

# 步骤2:在路径操作函数中引入公共类
@app.get("/item")
# 引入依赖类的简写方式为common:CommonQueryParams=Depends()
async def read_item(common:CommonQueryParams=Depends(CommonQueryParams)):
    return jsonable_encoder(common)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app="main:app",host="127.0.0.1",port=8080,reload=True)

测试结果如下:
在这里插入图片描述

对比函数依赖和类依赖的路径操作函数,需要注意:
在函数依赖中路径操作函数参数的类型声明为依赖函数的返回结果类型,Depends函数的参数是函数名
在类依赖中路径操作函数参数的类型声明为依赖类的类名,Depends函数的参数是依赖类名

嵌套依赖

fastapi中支持创建含依赖项的依赖项,并可以按需声明任意深度的子依赖项嵌套层级。

# 下面演示嵌套依赖
# 定义最外层依赖函数
def query_extractor(q:Union[str,None] = None):
	print("q")
    return q
# 定义依赖最外层依赖函数的依赖函数
def query_or_cookie_extractor(
    q:str=Depends(query_extractor),
    last_query:Union[str,None]=Cookie(default=None)
    ):
    print("cookie")
    if not q:
        return last_query
    return q
# 定义使用了嵌套依赖函数的路径操作函数
@app.post("/items")
def create_items(query_or_default:str = Depends(query_or_cookie_extractor)):
    return {"q_or_cookie":query_or_default}

从下图演示结果可以看出,fastapi运行依赖项时,最先运行最里层的依赖,然后依次运行外层的依赖项。
在这里插入图片描述
在这里插入图片描述

当路径操作函数中存在依赖项时,该路径操作函数的输入参数就是所有依赖项参数的和路径操作函数本身参数的集合。
上例的路径参数的输入参数是q查询参数和last_query cookie参数。

多次使用同一个依赖项

如果在同一个路径操作 多次声明了同一个依赖项,例如,多个依赖项共用一个子依赖项,FastAPI 在处理同一请求时,只调用一次该子依赖项。

FastAPI 不会为同一个请求多次调用同一个依赖项,而是把依赖项的返回值进行「缓存」,并把它传递给同一请求中所有需要使用该返回值的「依赖项」。

在高级使用场景中,如果不想使用「缓存」值,而是为需要在同一请求的每一步操作(多次)中都实际调用依赖项,可以把 Depends 的参数 use_cache 的值设置为 False

async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
    return {"fresh_value": fresh_value}

路径操作装饰器依赖项

当依赖项没有返回值,但是仍要执行或解析该依赖项时,就不必在声明路径操作函数的参数时使用Depends,而是可以在路径操作装饰器中添加一个由dependencies组成的列表。

async def verify_token(x_token:str=Header()):
    if not x_token:
        raise HTTPException(status_code=400,detail="not X-Token header invalid")

async def verify_key(x_key:str=Header()):
    if not x_key:
        raise HTTPException(status_code=400,detail="not X-Key header invalid")

@app.get("/student",dependencies=[Depends(verify_key),Depends(verify_token)])
async def read_student():
    return {"msg":"hello"}

从测试结果可以看出,这里的依赖都会被执行一次。
在这里插入图片描述

全局依赖

当依赖项被每个路径操作函数依赖时,我们可以通过添加全局依赖的方式为每个路径操作函数添加依赖。而避免了在每个路径操作函数或路径装饰器中添加依赖。
这主要是通过在FastAPI创建实例对象时使用dependencies参数。

# 演示创建全局依赖,被某个应用中的所有路径依赖
app1 = FastAPI(dependencies=[Depends(verify_key),Depends(verify_token)])
@app1.get("/student")
async def read_student():
    return {"msg":"hello"}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习_程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值