Fastapi 迁移模型、token 认证、中间件、CORS、后台任务、测试用例
alembic 迁移模型
pip install alembic=1.13.1
初始化Alembic 项目
alembic init alembic
会生成alebic.ini文件 修改里面的数据库连接
[alembic] script_location = alembic sqlalchemy.url = mysql+pymysql://david:123456@localhost/summary [loggers] keys = root [handlers] keys = console [formatters] keys = generic [logger_root] level = WARN handlers = console qualname = [handler_console] class = StreamHandler args = (sys.stderr,) level = NOTSET formatter = generic [formatter_generic] format = %(levelname)-5.5s [%(name)s] %(message)s
alembic/env.py,修改meatadata中的信息,是target_matadata指向项目中真实的路径
from models import Base target_metadata = Base.metadata
创建一个表,生成迁移文件
alembic revision --autogenerate -m "create_user_table"
执行迁移
alembic upgrade head
后续添加字段只需重复执行下面的两条命令即可
alembic revision --autogenerate -m "add phone field to user" alembic upgrade head
用户认证
from fastapi import FastAPI, Security, HTTPException from fastapi.security import APIKeyHeader app = FastAPI() api_key = APIKeyHeader(name="api_key") @app.get("/protected") async def protected_route(api_key: str = Security(api_key)): if api_key != "your_api_key": raise HTTPException(status_code=401, detail="Invalid API key") return current_user
常用中间件
from fastapi.middleware.cors import CORSMiddleware @app.middleware('http') async def add_process_time_header(request: Request, call_next): # call_next将接收request请求做为参数 start_time = time.time() response = await call_next(request) process_time = time.time() - start_time response.headers['X-Process-Time'] = str(process_time) # 添加自定义的以“X-”开头的请求头 return response app.add_middleware( CORSMiddleware, allow_origins=[ "*" ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
实现类似celery 的后台任务
BackgroundTasks 开启后台任务
from typing import Optional from fastapi import APIRouter, BackgroundTasks, Depends app08 = APIRouter() def bg_task(framework: str): with open("README.md", mode="a") as f: f.write(f"test") @app08.post("/background_tasks") async def run_bg_task(framework: str, background_tasks: BackgroundTasks): """ :param framework: 被调用的后台任务函数的参数 :param background_tasks: FastAPI.BackgroundTasks :return: """ background_tasks.add_task(bg_task, framework) return {"message": "任务已在后台运行"}
引入其他的BackgroundTasks
#!/usr/bin/python3 # -*- coding:utf-8 -*- # __author__ = '__Jack__' from typing import Optional from fastapi import APIRouter, BackgroundTasks, Depends app08 = APIRouter() """Background Tasks 后台任务""" def bg_task(framework: str): with open("README.md", mode="a") as f: f.write(f"test") def continue_write_readme(background_tasks: BackgroundTasks, q: Optional[str] = None): if q: background_tasks.add_task(bg_task, "\n> 整体的介绍 FastAPI,快速上手开发,结合 API 交互文档逐个讲解核心模块的使用\n") return q @app08.post("/dependency/background_tasks") async def dependency_run_bg_task(q: str = Depends(continue_write_readme)): if q: return {"message": "README.md更新成功"}
需要注意的点,不要在后台任务中使用depends
def bg_task(url: HttpUrl, db: Session): """这里注意一个坑,不要在后台任务的参数中db: Session = Depends(get_db)这样导入依赖"""
编写单元测试用例
#!/usr/bin/python3 # -*- coding:utf-8 -*- # __author__ = '__Jack__' from fastapi.testclient import TestClient from run import app """Testing 测试用例""" client = TestClient(app) # 先pip install pytest def test_run_bg_task(): # 函数名用“test_”开头是 pytest 的规范。注意不是async def response = client.post(url="/chapter08/background_tasks?framework=FastAPI") assert response.status_code == 200 assert response.json() == {"message": "任务已在后台运行"} def test_dependency_run_bg_task(): response = client.post(url="/chapter08/dependency/background_tasks") assert response.status_code == 200 assert response.json() is None def test_dependency_run_bg_task_q(): response = client.post(url="/chapter08/dependency/background_tasks?q=1") assert response.status_code == 200 assert response.json() == {"message": "README.md更新成功"}