logo

FastAPI 实战:待办事项路由的增删改查全流程指南

作者:demo2025.09.18 18:04浏览量:0

简介:本文详细讲解如何使用 FastAPI 快速构建一个支持增删改查(CRUD)的待办事项 Web API 项目,包含路由设计、模型定义、数据库集成及测试方法。

FastAPI 实战:待办事项路由的增删改查全流程指南

FastAPI 作为一款现代化的 Python Web 框架,以其高性能、自动生成 API 文档和类型提示支持等特性,成为开发 Web API 的理想选择。本文将通过一个完整的待办事项(Todo)项目,详细阐述如何使用 FastAPI 实现路由的增删改查(CRUD)功能,帮助开发者快速掌握 FastAPI 的核心开发技巧。

一、项目初始化与环境配置

1.1 环境搭建

首先,我们需要创建一个 Python 虚拟环境,并安装 FastAPI 及其依赖。推荐使用 pipenvpoetry 进行依赖管理,这里以 pipenv 为例:

  1. # 创建虚拟环境并安装 FastAPI
  2. pipenv install fastapi uvicorn[standard]
  3. # 安装数据库依赖(以 SQLite 为例)
  4. pipenv install sqlalchemy databases[sqlite]

1.2 项目结构规划

合理的项目结构有助于代码的可维护性。一个典型的 FastAPI 项目结构如下:

  1. todo_app/
  2. ├── main.py # 应用入口
  3. ├── models.py # 数据模型定义
  4. ├── schemas.py # 数据验证模型
  5. ├── crud.py # 数据库操作逻辑
  6. ├── database.py # 数据库连接与会话管理
  7. └── routers/ # 路由模块
  8. └── todos.py # 待办事项路由

二、数据模型与数据库集成

2.1 定义数据模型

models.py 中,我们使用 SQLAlchemy 定义待办事项的数据模型:

  1. from sqlalchemy import Column, Integer, String, Boolean
  2. from sqlalchemy.ext.declarative import declarative_base
  3. Base = declarative_base()
  4. class Todo(Base):
  5. __tablename__ = "todos"
  6. id = Column(Integer, primary_key=True, index=True)
  7. title = Column(String, index=True)
  8. description = Column(String)
  9. completed = Column(Boolean, default=False)

2.2 数据库连接与会话管理

database.py 中,我们配置数据库连接并创建会话工厂:

  1. from sqlalchemy import create_engine
  2. from sqlalchemy.orm import sessionmaker
  3. from .models import Base
  4. DATABASE_URL = "sqlite:///./todo.db"
  5. engine = create_engine(
  6. DATABASE_URL, connect_args={"check_same_thread": False}
  7. )
  8. SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
  9. Base.metadata.create_all(bind=engine)

2.3 创建数据库操作函数

crud.py 中,我们封装待办事项的 CRUD 操作:

  1. from sqlalchemy.orm import Session
  2. from . import models, schemas
  3. def get_todo(db: Session, todo_id: int):
  4. return db.query(models.Todo).filter(models.Todo.id == todo_id).first()
  5. def get_todos(db: Session, skip: int = 0, limit: int = 100):
  6. return db.query(models.Todo).offset(skip).limit(limit).all()
  7. def create_todo(db: Session, todo: schemas.TodoCreate):
  8. db_todo = models.Todo(title=todo.title, description=todo.description)
  9. db.add(db_todo)
  10. db.commit()
  11. db.refresh(db_todo)
  12. return db_todo
  13. def update_todo(db: Session, todo_id: int, todo: schemas.TodoUpdate):
  14. db_todo = get_todo(db, todo_id)
  15. if db_todo:
  16. db_todo.title = todo.title or db_todo.title
  17. db_todo.description = todo.description or db_todo.description
  18. db_todo.completed = todo.completed if todo.completed is not None else db_todo.completed
  19. db.commit()
  20. return db_todo
  21. def delete_todo(db: Session, todo_id: int):
  22. db_todo = get_todo(db, todo_id)
  23. if db_todo:
  24. db.delete(db_todo)
  25. db.commit()
  26. return db_todo

三、路由设计与实现

3.1 定义请求与响应模型

schemas.py 中,我们使用 Pydantic 定义请求和响应的数据模型:

  1. from pydantic import BaseModel
  2. class TodoBase(BaseModel):
  3. title: str
  4. description: str | None = None
  5. class TodoCreate(TodoBase):
  6. pass
  7. class TodoUpdate(BaseModel):
  8. title: str | None = None
  9. description: str | None = None
  10. completed: bool | None = None
  11. class Todo(TodoBase):
  12. id: int
  13. completed: bool
  14. class Config:
  15. orm_mode = True

3.2 实现待办事项路由

routers/todos.py 中,我们定义待办事项的 CRUD 路由:

  1. from fastapi import APIRouter, Depends, HTTPException
  2. from sqlalchemy.orm import Session
  3. from .. import crud, schemas
  4. from ..database import SessionLocal
  5. router = APIRouter()
  6. def get_db():
  7. db = SessionLocal()
  8. try:
  9. yield db
  10. finally:
  11. db.close()
  12. @router.get("/todos/", response_model=list[schemas.Todo])
  13. def read_todos(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
  14. todos = crud.get_todos(db, skip=skip, limit=limit)
  15. return todos
  16. @router.post("/todos/", response_model=schemas.Todo)
  17. def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
  18. return crud.create_todo(db=db, todo=todo)
  19. @router.get("/todos/{todo_id}", response_model=schemas.Todo)
  20. def read_todo(todo_id: int, db: Session = Depends(get_db)):
  21. db_todo = crud.get_todo(db, todo_id=todo_id)
  22. if db_todo is None:
  23. raise HTTPException(status_code=404, detail="Todo not found")
  24. return db_todo
  25. @router.put("/todos/{todo_id}", response_model=schemas.Todo)
  26. def update_todo(todo_id: int, todo: schemas.TodoUpdate, db: Session = Depends(get_db)):
  27. db_todo = crud.update_todo(db, todo_id=todo_id, todo=todo)
  28. if db_todo is None:
  29. raise HTTPException(status_code=404, detail="Todo not found")
  30. return db_todo
  31. @router.delete("/todos/{todo_id}")
  32. def delete_todo(todo_id: int, db: Session = Depends(get_db)):
  33. db_todo = crud.delete_todo(db, todo_id=todo_id)
  34. if db_todo is None:
  35. raise HTTPException(status_code=404, detail="Todo not found")
  36. return {"message": "Todo deleted successfully"}

3.3 集成路由到主应用

main.py 中,我们集成路由并启动应用:

  1. from fastapi import FastAPI
  2. from .routers import todos
  3. app = FastAPI()
  4. app.include_router(todos.router)
  5. # 启动命令:uvicorn main:app --reload

四、测试与验证

4.1 使用 HTTP 客户端测试

FastAPI 自动生成交互式 API 文档(访问 /docs),我们可以使用它进行测试:

  1. 创建待办事项

    • 方法:POST
    • 路径:/todos/
    • 请求体:
      1. {
      2. "title": "学习 FastAPI",
      3. "description": "完成待办事项路由的增删改查"
      4. }
  2. 查询待办事项

    • 方法:GET
    • 路径:/todos/
  3. 更新待办事项

    • 方法:PUT
    • 路径:/todos/{todo_id}
    • 请求体:
      1. {
      2. "completed": true
      3. }
  4. 删除待办事项

    • 方法:DELETE
    • 路径:/todos/{todo_id}

4.2 编写单元测试

使用 pytest 编写单元测试,验证路由逻辑的正确性:

  1. from fastapi.testclient import TestClient
  2. from sqlalchemy import create_engine
  3. from sqlalchemy.orm import sessionmaker
  4. from main import app
  5. from database import Base
  6. SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
  7. engine = create_engine(
  8. SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
  9. )
  10. TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
  11. Base.metadata.create_all(bind=engine)
  12. def override_get_db():
  13. try:
  14. db = TestingSessionLocal()
  15. yield db
  16. finally:
  17. db.close()
  18. app.dependency_overrides[get_db] = override_get_db
  19. client = TestClient(app)
  20. def test_create_todo():
  21. response = client.post(
  22. "/todos/",
  23. json={"title": "测试待办", "description": "测试描述"},
  24. )
  25. assert response.status_code == 200
  26. assert response.json()["title"] == "测试待办"
  27. def test_read_todos():
  28. response = client.get("/todos/")
  29. assert response.status_code == 200
  30. assert isinstance(response.json(), list)

五、优化与扩展建议

5.1 性能优化

  1. 异步支持:FastAPI 原生支持异步,可以将数据库操作改为异步(如使用 asyncpgsqlalchemy[asyncio])。
  2. 缓存层:引入 Redis 缓存频繁查询的数据,减少数据库压力。
  3. 分页优化:在查询大量数据时,实现更高效的分页逻辑。

5.2 功能扩展

  1. 用户认证:集成 JWT 或 OAuth2 实现用户认证。
  2. 标签系统:为待办事项添加标签,支持按标签筛选。
  3. 定时任务:使用 Celery 实现待办事项的定时提醒。

5.3 部署建议

  1. 容器化:使用 Docker 打包应用,便于部署。
  2. CI/CD:集成 GitHub Actions 或 GitLab CI 实现自动化测试和部署。
  3. 监控:使用 Prometheus 和 Grafana 监控应用性能。

六、总结

通过本文,我们详细讲解了如何使用 FastAPI 快速开发一个支持增删改查的待办事项 Web API 项目。从环境配置、数据模型定义、路由设计到测试验证,我们覆盖了 FastAPI 开发的核心流程。FastAPI 的高性能和易用性使其成为开发 Web API 的理想选择,而合理的项目结构和代码组织则能显著提升开发效率和代码质量。希望本文能为开发者提供实用的指导,助力快速掌握 FastAPI 的开发技巧。

相关文章推荐

发表评论