从‘能用’到‘好维护’:我是如何优化一个FastAPI小项目的目录和命名的

发布时间:2026/5/19 14:31:55

从‘能用’到‘好维护’:我是如何优化一个FastAPI小项目的目录和命名的 从‘能用’到‘好维护’我是如何优化一个FastAPI小项目的目录和命名的1. 混乱的开端当能跑就行变成寸步难行三周前当我第一次用FastAPI完成那个简单的用户管理系统时内心充满了成就感。所有功能都塞在了一个200行的main.py里数据库连接直接写在路由函数里用户模型和API响应模型混为一谈甚至密码哈希函数就放在/register端点下方。当时觉得这很高效——毕竟整个项目只有我一个人在用。直到上周产品经理提出要增加手机号验证功能时我才意识到问题的严重性# 原始main.py片段灾难现场 app.post(/register) async def register(username: str, password: str): # 密码哈希函数直接内嵌 def hash_password(pwd): return hashed_ pwd # 数据库连接硬编码 conn sqlite3.connect(users.db) cursor conn.cursor() # 业务逻辑与SQL语句混杂 cursor.execute(fINSERT INTO users VALUES ({username}, {hash_password(password)})) conn.commit() return {message: User created}暴露的核心问题任何修改都可能引发连锁反应无法单独测试密码哈希逻辑数据库连接分散在各处模型定义重复且不一致提示当你在同一个文件里使用CtrlF查找超过5次时就该考虑重构了2. 重构路线图从混沌到清晰2.1 第一步建立项目骨架我参考了Python社区广泛采用的src布局但针对FastAPI特性做了调整my_project/ ├── .env # 环境配置 ├── requirements.txt # 依赖清单 ├── tests/ # 测试专用目录 └── src/ # 主要代码库 ├── __init__.py ├── main.py # 精简后的入口文件 ├── api/ │ └── v1/ # 版本隔离 ├── core/ # 配置和工具 ├── models/ # SQLAlchemy模型 ├── schemas/ # Pydantic模型 └── utils/ # 辅助函数关键决策点使用src布局避免Python包导入陷阱早期引入v1/为API演进留空间严格区分数据模型models和接口模型schemas2.2 模型分离的艺术原先混乱的模型定义被拆分为两个明确的部分# models/user.py (数据库层) from sqlalchemy import Column, String class User(Base): __tablename__ users username Column(String, primary_keyTrue) hashed_password Column(String)# schemas/user.py (接口层) from pydantic import BaseModel class UserCreate(BaseModel): username: str password: str class UserResponse(BaseModel): username: str这种分离带来三个优势数据库模型可以自由调整而不影响API契约输入验证逻辑集中管理文档生成更加准确3. 依赖管理的进化之路3.1 从硬编码到依赖注入原始代码中随处可见的数据库连接被重构为集中管理# core/database.py from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine create_engine(config.DATABASE_URL) SessionLocal sessionmaker(autocommitFalse, bindengine) def get_db(): db SessionLocal() try: yield db finally: db.close()然后在路由中优雅地使用# api/v1/endpoints/users.py from fastapi import Depends from sqlalchemy.orm import Session app.post(/users) def create_user(user: UserCreate, db: Session Depends(get_db)): # 业务逻辑 db.add(user) db.commit()3.2 依赖项分类管理我将依赖项按功能划分到不同文件dependencies/ ├── __init__.py ├── auth.py # 认证相关 ├── database.py # 数据库会话 └── logging.py # 日志配置这种结构使得每个依赖项都有明确的归属避免循环导入问题便于单元测试mock4. 命名规范的实战经验4.1 文件命名对照表旧命名新命名改进点userStuff.pyservices/user.py明确模块职责db_funcs.pycrud/items.py符合CRUD模式config.txt.env符合行业标准4.2 API路由命名原则经过多次迭代我总结出这些规则资源使用复数形式/users而非/user动作使用动词前缀POST /users/import关系使用嵌套结构/users/{id}/orders过滤参数统一格式/users?activetrue反面案例app.get(/getUserList) # 动词名词混合 app.post(/new_item) # 命名风格不一致优化后app.get(/users) # 纯资源导向 app.post(/items) # 统一风格5. 测试套件的重生原先根本无法测试的代码现在有了完整的测试覆盖# tests/test_users.py def test_create_user(client): response client.post( /v1/users, json{username: test, password: secret} ) assert response.status_code 201 assert username in response.json()测试目录结构与主代码保持镜像关系tests/ ├── __init__.py ├── conftest.py # 全局fixture └── api/ └── v1/ ├── test_users.py └── test_items.py6. 工具链的统一配置在项目根目录添加这些文件后协作变得轻松许多# .pre-commit-config.yaml repos: - repo: https://github.com/psf/black rev: 22.3.0 hooks: - id: black args: [--line-length88]# pyproject.toml [tool.black] line-length 88 target-version [py310]这些配置确保代码风格自动统一提交前自动检查团队协作无摩擦7. 重构后的效率提升指标对比维度重构前重构后添加新功能时间3小时45分钟测试覆盖率0%85%构建失败次数每周2-3次近一月0次最让我惊喜的是当新同事加入项目时他仅用半小时就完成了开发环境搭建和第一个PR提交。这种可维护性带来的团队效能提升远比个人编码时的快捷更有价值。

相关新闻