Skip to content

Commit b0b1670

Browse files
committed
第五章 FastAPI的依赖注入系统
1 parent 34dc913 commit b0b1670

File tree

3 files changed

+133
-71
lines changed

3 files changed

+133
-71
lines changed

run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from starlette.exceptions import HTTPException as StarletteHTTPException
1010

1111
from coronavirus import application
12-
from tutorial import app03, app04
12+
from tutorial import app03, app04, app05
1313

1414
app = FastAPI(
1515
title='FastAPI Tutorial and Coronavirus Tracker API Docs',
@@ -42,6 +42,7 @@
4242

4343
app.include_router(app03, prefix="/chapter03", tags=['第三章 请求参数和验证'])
4444
app.include_router(app04, prefix="/chapter04", tags=['第四章 响应处理和FastAPI配置'])
45+
app.include_router(app05, prefix="/chapter05", tags=['第五章 FastAPI的依赖注入系统'])
4546
app.include_router(application, prefix="/coronavirus", tags=['新冠病毒疫情跟踪器API'])
4647

4748
if __name__ == '__main__':

tutorial/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
# __author__ = '__Jack__'
44

55
from .chapter03 import app03
6+
from .chapter04 import app04
7+
from .chapter05 import app05

tutorial/chapter05.py

Lines changed: 129 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,132 @@
22
# -*- coding:utf-8 -*-
33
# __author__ = '__Jack__'
44

5-
# from typing import List
6-
#
7-
# from fastapi import Form, File, UploadFile
8-
# from starlette.requests import Request
9-
#
10-
# from fastapi import APIRouter
11-
#
12-
#
13-
# app02 = APIRouter()
14-
#
15-
#
16-
# @app02.post("/user/")
17-
# async def login_post(request: Request, username: str = Form(...), password: str = Form(...)):
18-
# """
19-
# Form表单操作
20-
# :param request:
21-
# :param username:
22-
# :param password:
23-
# :return:
24-
# """
25-
#
26-
# print(f"username: {username}, password: {password}")
27-
#
28-
# return templates.TemplateResponse("post.html", {"request": request, "username": username, "password": password})
29-
#
30-
#
31-
# @app02.get("/user/")
32-
# async def login_get(request: Request):
33-
# return templates.TemplateResponse("post.html", {"request": request})
34-
#
35-
#
36-
# @app02.get("/file/")
37-
# async def login_get(request: Request):
38-
# return templates.TemplateResponse("file.html", {"request": request})
39-
#
40-
#
41-
# @app02.post("/file/")
42-
# async def upload_file(request: Request, files_list: List[bytes] = File(...), files_name: List[UploadFile] = File(...)):
43-
# """
44-
# 上传多个文件
45-
# :param request:
46-
# :param files_list: List[bytes]表示可上传多个文件,bytes表示上传一个文件
47-
# :param files_name:
48-
# :return:
49-
# """
50-
#
51-
# return templates.TemplateResponse("file.html", {
52-
# "request": Request,
53-
# "file_sizes": [len(file) for file in files_list], # 用字节长度表示文件大小
54-
# "filenames": [file.filename for file in files_name]
55-
# })
56-
#
57-
#
58-
# @app02.post("/create_file/")
59-
# async def create_file(request: Request, file1: bytes = File(...), file2: UploadFile = File(...), notes: str = Form(...)):
60-
# """
61-
# 上传单个文件
62-
# :param request:
63-
# :param file1: bytes类型可以统计长度,但是没有content_type属性
64-
# :param file2: UploadFile类有content_type属性,但是不能len()统计文件长度
65-
# :param notes:
66-
# :return:
67-
# """
68-
#
69-
# return templates.TemplateResponse("file.html", {
70-
# "request": Request,
71-
# "file_size": len(file1),
72-
# "notes": notes,
73-
# "file2_content_type": file2.content_type
74-
# })
5+
from typing import Optional
6+
7+
from fastapi import APIRouter
8+
from fastapi import Depends, HTTPException, Header
9+
10+
app05 = APIRouter()
11+
12+
"""Dependencies 导入、创建和声明依赖"""
13+
14+
15+
async def common_parameters(q: Optional[str] = None, page: int = 1, limit: int = 100):
16+
return {"q": q, "page": page, "limit": limit}
17+
18+
19+
@app05.get("/dependency01")
20+
async def dependency01(commons: dict = Depends(common_parameters)):
21+
return commons
22+
23+
24+
@app05.get("/dependency02")
25+
def dependency02(commons: dict = Depends(common_parameters)): # 可以在async def中调用def依赖,也可以在def中导入async def依赖
26+
return commons
27+
28+
29+
"""Classes as Dependencies 类作为依赖项"""
30+
31+
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
32+
33+
34+
class CommonQueryParams:
35+
def __init__(self, q: Optional[str] = None, page: int = 1, limit: int = 100):
36+
self.q = q
37+
self.page = page
38+
self.limit = limit
39+
40+
41+
@app05.get("/classes_as_dependencies")
42+
# async def classes_as_dependencies(commons: CommonQueryParams = Depends(CommonQueryParams)):
43+
# async def classes_as_dependencies(commons: CommonQueryParams = Depends()):
44+
async def classes_as_dependencies(commons=Depends(CommonQueryParams)):
45+
response = {}
46+
if commons.q:
47+
response.update({"q": commons.q})
48+
items = fake_items_db[commons.page: commons.page + commons.limit]
49+
response.update({"items": items})
50+
return response
51+
52+
53+
"""Sub-dependencies 子依赖"""
54+
55+
56+
def query(q: Optional[str] = None):
57+
return q
58+
59+
60+
def sub_query(q: str = Depends(query), last_query: Optional[str] = None):
61+
if not q:
62+
return last_query
63+
return q
64+
65+
66+
@app05.get("/sub_dependency")
67+
async def sub_dependency(final_query: str = Depends(sub_query, use_cache=True)):
68+
"""use_cache默认是True, 表示当多个依赖有一个共同的子依赖时,每次request请求只会调用子依赖一次,多次调用将从缓存中获取"""
69+
return {"sub_dependency": final_query}
70+
71+
72+
"""Dependencies in path operation decorators 路径操作装饰器中的多依赖"""
73+
74+
75+
async def verify_token(x_token: str = Header(...)):
76+
"""没有返回值的子依赖"""
77+
if x_token != "fake-super-secret-token":
78+
raise HTTPException(status_code=400, detail="X-Token header invalid")
79+
80+
81+
async def verify_key(x_key: str = Header(...)):
82+
"""有返回值的子依赖,但是返回值不会被调用"""
83+
if x_key != "fake-super-secret-key":
84+
raise HTTPException(status_code=400, detail="X-Key header invalid")
85+
return x_key
86+
87+
88+
@app05.get("/dependency_in_path_operation", dependencies=[Depends(verify_token), Depends(verify_key)]) # 这时候不是在函数参数中调用依赖,而是在路径操作中
89+
async def dependency_in_path_operation():
90+
return [{"user": "user01"}, {"user": "user02"}]
91+
92+
93+
"""Global Dependencies 全局依赖"""
94+
95+
# app05 = APIRouter(dependencies=[Depends(verify_token), Depends(verify_key)])
96+
97+
98+
"""Dependencies with yield 带yield的依赖"""
99+
100+
101+
# 这个需要Python3.7才支持,Python3.6需要pip install async-exit-stack async-generator
102+
# 以下都是伪代码
103+
104+
async def get_db():
105+
db = "db_connection"
106+
try:
107+
yield db
108+
finally:
109+
db.endswith("db_close")
110+
111+
112+
async def dependency_a():
113+
dep_a = "generate_dep_a()"
114+
try:
115+
yield dep_a
116+
finally:
117+
dep_a.endswith("db_close")
118+
119+
120+
async def dependency_b(dep_a=Depends(dependency_a)):
121+
dep_b = "generate_dep_b()"
122+
try:
123+
yield dep_b
124+
finally:
125+
dep_b.endswith(dep_a)
126+
127+
128+
async def dependency_c(dep_b=Depends(dependency_b)):
129+
dep_c = "generate_dep_c()"
130+
try:
131+
yield dep_c
132+
finally:
133+
dep_c.endswith(dep_b)

0 commit comments

Comments
 (0)