FastApi学习-06

依赖注入

在看到这个词汇的时候,没有任何的概念。在翻阅一些资料之后,有了一点点眉目。对于类A,要是实现A的功能,必须要类B的功能。所以在A中实例化一个B。一旦B需要重构,由于A几乎完全依赖与B,所以A几乎也要重构。这是一种相当耦合的模式,依赖注入就是为了解决这种耦合性。A不再new一个B的实例,而是让B的一个实例作为A的一个成员存在,A不再关注B的实例化,只关注B的方法。(这是我的理解,也许有不对的地方)

在FastApi的框架中,依赖注入用于解决重复的逻辑代码,分享数据库的链接,统一验权等功能。旨在减少代码重复。

async def pagination(page_num: int = 1, page_count: int = 10):
    return {"page_num": page_num, "page_count": page_count}

@app.get("/request01")
async def request01(*, page: dict = Depends(pagination), c: int):
    return [page, c]

使用Depends实现依赖注入,pagination方法接收的page_num当前页码数,page_count每页的数据量,经过处理后返回给page一个起始结束下标的范围字典。在这个例子中来看,和其实现的功能和装饰器有点像,对于request01,不关注我接受了什么数据,只希望获取分页的下标范围,而pagination方法实现了该功能,这样当分页的数据格式发生变更时,也只需要改变pagination方法。

类依赖

上面注入的依赖是以函数的形式,其实对于FastApi,能够作为依赖的关键是是否能够被调用(callable),所以Python class类也可以作为依赖被注入。

class Pagination:
    def __init__(self, page_num: int = 1, page_count: int = 10):
        self.page_start = (page_num - 1) * page_count
        self.page_end = page_num * page_count - 1

@app.get("/request02")
async def request02(*, page: Pagination = Depends(Pagination)):
    return page

Pagination作为类依赖被注入到request02中,注意Pagination的__init__方法创建了一个Pagination的实例。

子依赖

async def pagination1(page: dict = Depends(pagination), other: int = 0):
    page.update({"other": other})
    return page

@app.get("/request03")
async def request03(page: dict = Depends(pagination1)):
    return page

request03方法中依赖了pagination1, 而pagination1中又依赖了pagination,这是依赖的嵌套。在最终的调用中,使用最底层的参数,例如在调用request03时,传入的参数是other, 以及pagination中的page_num, page_count。

路由装饰器依赖

async def verify_header(token: str = Header(...)):
    print(token)

async def verify_query(name: str = Query(...)):
    print(name)

@app.get("/request04", dependencies=[Depends(verify_header), Depends(verify_query)])
def request04():
    return "hello world"

当我不关注依赖的返回值时,可以将依赖注入到路由装饰器中,使用dependencies关键字,数组类型的依赖。无论依赖函数是否有返回,在接口函数中都不会使用。

中间件简介

# 中间件简介
@app.middleware("http")
async def get_response_time(request: Request, call_next):
    start_time = datetime.now()
    response = await call_next(request)
    end_time = datetime.now()
    print(end_time.timestamp() - start_time.timestamp())
    return response

当前只支持http的中间件,在await call_next()之前初始化一些数据,在之后是调用完接口,返回响应之前。在这里可以记录接口的响应时间,sql查询的次数等。

跨域问题

app.add_middleware(app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
))

基于starletter实现的跨域中间件,解决跨域问题。

后台任务

# 后台任务
def bktask():
    for i in range(10):
        print(i)
        time.sleep(2)

@app.get("/request05")
def request05(backtask: BackgroundTasks):
    backtask.add_task(bktask)
    return "hello world"

在request05方法中,接收一个BackgroundTasks后台任务列表,然后向backtask中添加后台任务,在任务添加完成后,不用等待后台任务执行完毕,就返回响应了。后台任务会继续执行直到结束。

文档配置

app = FastAPI(title="1", description="2", version="3", docs_url="/mydoc")

在实例化FastApi的时候,传入参数来配置其文档信息。

title,description,version是对于api文档的描述信息,docs_url修改其文档的地址。

app.mount("/static", StaticFiles(directory="static"), name="123")

首先pip安装aiofiles,然后由fastapi导入StaticFiles,然后将静态文件的路径绑定上。其中"/static"是前缀路径,directory是静态文件所在的路径,name无所谓。

测试

from .main import app

from fastapi.testclient import TestClient

client = TestClient(app)


def test_abc():
    response = client.get("/request04")
    assert response.status_code == 422

以上是单元测试文件,需要先pip安装pytest与requests。

写在后面

跟着官方文档的FastApi的基础学习到这里基本上算是结束了,既然学习了,就要付诸实践,我的想法是模仿flask的教程,完成一个简单的博客系统,采用前后端分离的方式,后端使用FastApi,前端使用React框架。

当然了,官网的还有进阶的内容,也会一边学习一边更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值