Python本科毕业设计源码实战:从零构建可扩展的Web应用架构
摘要:许多本科生在完成毕业设计时,常把 Python 项目写成“单文件脚本”,缺乏模块化、可维护性和部署能力。本文以典型毕业设计场景(教务管理系统、图书推荐平台)为例,系统讲解如何基于 Flask/FastAPI 构建分层清晰、数据库解耦、接口规范的工程化源码结构。读完你将掌握配置管理、日志监控、API 文档自动生成等关键实践,显著提升代码质量与答辩表现。
一、毕业设计常见代码反模式与维护痛点
先别急着写代码,看看下面这些“熟悉的味道”你有没有中招:
- 所有逻辑挤在
app.py一个文件,路由、SQL、业务算法全混在一起,后期改一行代码要翻半天。 - 配置写死:
DB_HOST = "127.0.0.1"、SECRET = "123456",换电脑或上线就炸。 - 异常裸奔,前端直接收到 500 错误页面,答辩现场演示一旦报错直接“社死”。
- 没有 requirements.txt 或版本号随意写,换台机器
pip install后依赖冲突,运行不起来。 - 数据库字段一改,手动改 SQL,忘记改某张表,程序跑通但数据插不进去。
痛点一句话总结:“能跑”≠“能维护”。老师问“后续如何加功能”时,你只能尴尬微笑。下面我们用工程化思路把这些坑一次填平。
二、Flask vs FastAPI:小项目如何二选一
| 维度 | Flask | FastAPI |
|---|---|---|
| 学习曲线 | 平缓,文档多 | 需先理解异步、类型注解 |
| 性能 | WSGI 同步,够用 | ASGI 异步,并发更高 |
| 自动生成文档 | 需集成 flask-restx 或 flasgger | 原生/docs红页 |
| 数据校验 | 手动写或 marshmallow | 基于 Pydantic,自动生成 |
| 生态老插件 | 非常丰富 | 相对年轻 |
结论:
- 想快速出活、老师只要求“功能+界面”,选 Flask。
- 想秀性能、接口文档一键生成、顺便学异步,选 FastAPI。
下面示范以 FastAPI 为主,Flask 目录结构同理,只需把路由装饰器换掉即可。
三、分层架构:routes / models / utils / config
先给目录树,让“哪里放什么”一目了然:
graduation_project/ ├─ app/ │ ├─ __init__.py │ ├─ main.py # 入口,只负责注册路由、中间件 │ ├─ config.py # 所有可配项集中管理 │ ├─ models/ # SQLAlchemy ORM 实体 │ ├─ routers/ # 业务路由 │ ├─ schemas/ # Pydantic 校验模型 │ ├─ service/ # 复杂业务逻辑抽离 │ ├─ utils/ # 工具:日志、JWT、分页 │ └─ db.py # 创建 engine & SessionLocal ├─ tests/ # pytest 单元测试 ├─ scripts/ # 初始化脚本、迁移 ├─ Dockerfile ├─ docker-compose.yml └─ requirements.txt核心实现片段(省略 import,完整文件放 GitHub):
- config.py —— 一处配置到处用
from pydantic import BaseSettings class Settings(BaseSettings): db_url: str = "sqlite:///./dev.db" jwt_secret: str = "CHANGE_ME" jwt_expire: int = 60 * 24 * 8 # 8 天 class Config: env_file = ".env" # 本地调试可覆盖 settings = Settings()- db.py —— 全局依赖注入
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from .config import settings engine = create_engine(settings.db_url, pool_pre_ping=True, echo=False) SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False) # FastAPI 的依赖 def get_db(): db = SessionLocal() try: yield db finally: db.close()- models/book.py —— ORM 实体
from sqlalchemy import Column, Integer, String from app.db import Base class Book(Base): __tablename__ = "books" id = Column(Integer, primary_key=True, index=True) title = Column(String(120), nullable=False, index=True) author = Column(String(60), nullable=False)- schemas/book.py —— Pydantic 校验
from pydantic import BaseModel, Field class BookCreate(BaseModel): title: str = Field(..., min_length=1, max_length=120) author: str = Field(..., max_length=60) class BookOut(BookCreate): id: int class Config: orm_mode = True- routers/book.py —— 只写“接收-校验-调用服务-返回”
from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.db import get_db from app.models.book import Book from app.schemas.book import BookCreate, BookOut router = APIRouter(prefix="/books", tags=["books"]) @router.post("", response_model=BookOut) def create_book(obj: BookCreate, db: Session = Depends(get_db)): db_obj = Book(**obj.dict()) db.add(db_obj); db.commit(); db.refresh(db_obj) return db_obj- main.py —— 胶水层
from fastapi import FastAPI from app.routers import book app = FastAPI(title="毕业设计图书推荐系统") app.include_router(book.router) # 自动生成文档已集成,访问 127.0.0.1:8000/docs 即可调试运行:
uvicorn app.main:app --reload浏览器打开/docs就能看到交互式 Swagger,老师现场演示也能稳住。
四、集成 SQLAlchemy ORM + Pydantic + Swagger 小结
- ORM 让你用 Python 类写 SQL,字段一改只需迁移脚本,不再手敲
ALTER TABLE。 - Pydantic 自动校验:字段长度、类型、必填项,一旦非法直接返回 422,前端同学会感谢你。
- FastAPI 自带 Swagger,接口即文档;Flask 可装
flasgger同样能生成,但要多写 YAML 注释。
一句话:把“裸 SQL”换成“ORM+模型校验”,答辩时老师问“如何防止 SQL 注入”就能自信回答:“SQLAlchemy 已参数化,且业务层不做字符串拼接”。
五、本地开发 vs 云部署:差异到底在哪
- 本地 SQLite 一键启动,适合写 demo;上线后 MySQL/PostgreSQL 才经得起并发。
- 本地
.env写数据库地址即可;云服务器要用环境变量,避免把密码打进镜像。 - Vercel 只支持无状态函数,数据库需用第三方托管(如 PlanetScale);Docker + 云主机自由度更高,还能配 Nginx、HTTPS。
- 端口暴露:本地
127.0.0.1:8000随便用;云主机要在安全组放行,并配 systemd 或 docker-compose 保活。 - 日志持久化:本地看控制台;线上要挂载 volume 或接入 Loki、ELK,否则容器重启日志全丢。
六、生产环境避坑指南
- 环境变量管理:用
python-dotenv只在开发加载;生产一律读系统变量,CI 侧写入 secret,不在仓库留痕。 - 异常处理粒度:路由层只捕获业务已知异常,未知异常要统一走
middleware包一层,返回{code, message},避免泄露栈信息。 - 避免硬编码:文件路径用
Path(__file__).resolve(),日志名用%(name)s,迁移脚本用alembic版本号,不走“手工复制”。 - 数据库连接池:默认 5 个连接在小水管服务器够用,但 Docker 容器 CPU 限额低时,要调低
pool_size,否则高并发直接拖垮。 - 静态文件:FastAPI 可用
StaticFiles,但生产环境推荐 CDN 或 Nginx 反向代理,减轻 Python 进程压力。 - 测试覆盖:至少把关键 service 层做
pytest单元测试,GitHub Actions 跑测试通过再合并,老师一看 CI 绿标,印象分++。
七、可拓展方向(写进论文里很加分)
- 加缓存:Redis +
aioredis,把热门图书信息缓存 30 秒,QPS 翻倍。 - 用户权限:JWT +
fastapi-users,实现教师/学生双角色,演示时切换账号,仪式感满满。 - 推荐算法:用
scikit-learn离线训练协同过滤模型,把模型文件.pkl放app/models_ml/,接口异步读取,秒变“智能推荐”。 - 日志可视化:接入 Grafana + Loki,答辩大屏一展示,全场焦点。
- 前端分离:Vue3 + Vite,接口 CORS 一开,就是现代化全栈项目。
八、结语:把毕设代码从“能跑”升级到“能见人”
毕业设计不是写完功能就结束,而是第一次向“工程级”迈进的练兵。把单文件拆成多层、把配置抽离、把接口文档自动化,再让 CI 跑通测试,你提交的不只是源码,而是一个可迭代、可部署、可协作的小型产品。现在就打开你的旧项目,参考上面的目录结构重构,push 到 GitHub,加一套 GitHub Actions 做自动测试与部署,让面试官和老师直接在线体验。下一步,把链接写进简历,你的 Python 旅程才真正起飞。