背景:为什么“任务管理”也能算新颖?
每年答辩季,老师最怕听到“图书管理系统”“学生成绩管理”这类祖传选题。不是功能不好,而是重复率太高,GitHub 上一搜一大把,答辩时还没开口,老师已经猜到你要讲什么。
想跳出同质化,其实不必另起炉灶,把“老场景”用“新思路”再做一遍,就能让评委眼前一亮。
“新”可以体现在三点:
- 技术栈轻量——用纯 Python 搞定全栈,零配置就能跑;
- 架构思想现代——RESTful 接口 + 前后端分离,哪怕前端暂时只写静态页,也预留了升级空间;
- 代码可验证——仓库里直接
python app.py就能跑,老师当场点开演示,可信度瞬间拉满。
下面这套“Flask + SQLite 任务管理系统”就是按这个思路撸出来的,适合零基础、时间紧、又想拿高分的同学。
技术选型:为什么不是 Django / Node.js?
毕设最怕“折腾环境”。Django 功能全,但 settings 一报错新手就懵;Node.js 生态丰富,可 npm 版本冲突能把人劝退。
对比之后我选了“Flask + SQLite”组合,理由简单粗暴:
| 维度 | Flask+SQLite | Django | Node.js(Express) |
|---|---|---|---|
| 学习曲线 | 1 个 py 文件就能跑 | 配置多、概念多 | 需懂异步、npm 生态 |
| 部署难度 | 自带调试服务器,生产可 gunicorn | wsgi + nginx 一堆配置 | pm2、nginx 双配置 |
| 资源占用 | 10 MB 左右 | 50 MB 起步 | 30 MB 起步 |
| 文档友好度 | 官方文档短、示例多 | 厚重、术语多 | 碎片化严重 |
一句话:先把项目跑起来,再谈优化。Flask “micro” 的哲学正好让毕设周期可控。
系统功能与架构速览
整个项目拆成 4 个蓝本(Blueprint),路由一眼能看懂:
- auth:注册、登录、退出
- task:任务的增删改查 + 状态切换
- api:JSON 接口,留给前端后续调用
- static:放 CSS/JS,让页面不裸奔
数据模型只有两张表,关系清晰,答辩画 ER 图 30 秒搞定:
- user(id, username, pw_hash)
- task(id, title, detail, status, created_at, user_id)
核心实现拆解
下面这段代码是整个工程的“最小可运行骨架”,复制到app.py直接python app.py即可启动。为了阅读顺畅,我拆分了 5 段讲解,每段都带注释,方便你二次改写。
1. 环境准备 & 项目初始化
# 建议建个 3.9+ 的虚拟环境 python -m venv venv source venv/bin/activate pip install flask flask_sqlalchemy werkzeug2. 数据库模型:两张表 + 外键
# app.py from flask import Flask, request, jsonify, redirect, url_for, session from flask_sqlalchemy import SQLAlchemy from werkzeug.security import generate_password_hash, check_password_hash import os, datetime app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(16) # 数据库文件就在项目根目录,毕设拷 U 盘时一起带走 app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///task.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, nullable=False) pw_hash = db.Column(db.String(128), nullable=False) class Task(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(120), nullable=False) detail = db.Column(db.Text) status = db.Column(db.String(20), default='TODO') # TODO / DONE created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey('user.id'))3. 注册 & 登录:会话管理 + 防注入
@app.route('/register', methods=['POST']) def register(): username = request.form['username'].strip() password = request.form['password'] if not username or not password: return '用户名/密码不能为空', 400 if User.query.filter_by(username=username).first(): return '用户名已存在', 400 user = User(username=username, pw_hash=generate_password_hash(password)) db.session.add(user) db.session.commit() return redirect(url_for('login_page')) @app.route('/login', methods=['POST']) def login(): username = request.form['username'] password = request.form['password'] user = User.query.filter_by(username=username).first() if user and check_password_hash(user.pw_hash, password): session['uid'] = user.id return redirect(url_for('task_list')) return '用户名或密码错误', 403注意:
- 所有 SQL 操作都走 ORM,从根本上堵住拼接注入
- 明文密码一秒生成哈希,
check_password_hash内部含 salt,老师问“安全性”直接甩这段
4. 任务 CRUD:RESTful 风格,返回 JSON 可插 Vue
# 列表 + 创建 @app.route('/tasks', methods=['GET', 'POST']) def task_list(): if 'uid' not in session: return '请先登录', 401 if request.method == 'POST': title = request.json.get('title') detail = request.json.get('detail', '') task = Task(title=title, detail=detail, user_id=session['uid']) db.session.add(task) db.session.commit() return jsonify(id=task.id, title=task.title), 201 tasks = Task.query.filter_by(user_id=session['uid']).all() return jsonify([{'id': t.id, 'title': t.title, 'status': t.status} for t in tasks]) # 更新 + 删除 @app.route('/tasks/<int:task_id>', methods=['PUT', 'DELETE']) def task_detail(task_id): task = Task.query.get_or_404(task_id) if task.user_id != session.get('uid'): return '无权限', 403 if request.method == 'PUT': task.title = request.json.get('title', task.title) task.status = request.json.get('status', task.status) db.session.commit() return jsonify(msg='updated') if request.method == 'DELETE': db.session.delete(task) db.session.commit() return jsonify(msg='deleted')5. 运行入口 & 自动建表
if __name__ == '__main__': # 首次运行时创建库表 if not os.path.exists('task.db'): with app.app_context(): db.create_all() app.run(debug=True)至此,一个带用户体系、支持 JSON 接口的“任务管理”核心就完成了,代码总行数 < 200,答辩 PPT 贴源码也不占页数。
性能与安全:小项目也要讲基本功
- SQL 注入:ORM 过滤掉 99% 风险,手写 SQL 一定用参数绑定
- 会话固定:登录后重新生成
session.permanent = True+ 随机 SECRET_KEY - 并发写:SQLite 默认串行写,高并发场景会撞“Database is locked”。毕设演示量小无所谓,真部署可换 PostgreSQL,SQLAlchemy 一行配置就能切库
- 密码策略:前端再加一层
minlength="6",Werkzeug 的哈希算法已带 bcrypt 扩展位,老师问“有没有加盐”直接回答“官方自动完成”
生产环境踩坑记录
- 路径问题:Windows 不识别
sqlite:///task.db绝对路径,推荐保持默认相对路径,部署时把 db 文件放用户目录外,防重装系统被格掉 - 蓝图的循环导入:拆服务时别把
db对象写在蓝图内部,统一在工厂函数里生成,避免ImportError - Debug 模式:生产环境务必
debug=False,否则异常栈会暴漏 SECRET_KEY - 多进程写入:gunicorn 开 4 个 worker 时,SQLite 写锁会飙升,换成 PostgreSQL 或给任务表加“单进程队列”兜底
可继续加分的 3 个方向
- 登录体系升级:把 session 换成 JWT,实现“无状态”+ 移动端复用
- 前端框架:Vue/React 只调上面
/tasks接口,半小时套个 Element-UI,项目秒变 SPA - 上云:
- 服务器:腾讯云轻量 1C2G 够跑,系统镜像选 Ubuntu 20.04
- 容器化:写一行 Dockerfile,
FROM python:3.11-slim,再配 GitHub Actions 自动部署,CI/CD 写进论文里就是亮点
写在最后
整套代码从 0 到跑通我只花了两个晚上,注释比业务逻辑还多,适合刚学完 Python 基础、又想快速攒一个能演示的 Web 项目。
毕设不是工程巨无霸,而是“思路清晰 + 能跑 + 能讲”三件事。把这篇笔记当成起跑线,先把最小系统交上去,再在 JWT、前端、云原生里任选一个方向深挖,答辩时你就能自信地说:
“老师,我不仅做了任务管理,还预留了分布式扩展接口。”
代码仓库已经放在 GitHub,拿去改个名就能提交,别忘了给 README 截几张效果图——让评委一眼看懂,比十页代码清单更有说服力。祝你一次过审,毕业快乐!