• 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
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    完整代码:

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

    完整代码如下:

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

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

    对比函数依赖和类依赖的路径操作函数,需要注意:
    在函数依赖中路径操作函数参数的类型声明为依赖函数的返回结果类型,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}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    从下图演示结果可以看出,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}
    
    • 1
    • 2

    路径操作装饰器依赖项

    当依赖项没有返回值,但是仍要执行或解析该依赖项时,就不必在声明路径操作函数的参数时使用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"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    全局依赖

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

    # 演示创建全局依赖,被某个应用中的所有路径依赖
    app1 = FastAPI(dependencies=[Depends(verify_key),Depends(verify_token)])
    @app1.get("/student")
    async def read_student():
        return {"msg":"hello"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    java基础之Map集合
    (二)算法分析
    php laravel 文件上传 csrf 路由route name命名
    1.SpringSecurity认证核心机制
    python编程难在哪里?
    拼多多根据关键词取商品列表 API 返回值说明
    Mysql 45讲学习笔记(十)force index
    互联网快讯:腾讯会议应用市场正式上线;Soul赴港递交上市申请书
    页面置换算法
    联通边缘AI:打造“职业技能”,助力行业高质量发展
  • 原文地址:https://blog.csdn.net/baidu_38766791/article/details/127398006