简介:这是一份围绕学生请假管理场景的Python项目源码,适合高校课程设计、毕业设计或初学者练习Web/桌面端管理系统开发。压缩包共14个文件,包含8个pyc编译文件、5个py源代码文件与1个sql数据库脚本,合计仅21KB,整体轻量,便于快速解压和运行调试。已有1117人浏览或下载该资源,可见其对于同类课设需求具有一定参考价值。源码中除了Student.py、Stud.py、vacate.py等主要业务模块外,还提供qingjia.sql数据库初始化脚本,可帮助使用者快速搭建请假申请、审批与查询的数据表结构。源码覆盖了学生提交请假、教师审批、通知提醒、统计分析等常见环节,适合用来做系统设计参考。通过学习这套代码,可以理解请假流程的角色权限划分、申请单处理逻辑以及Python项目的基础文件组织方式,亦可作为二次开发和功能扩展的起点。
1. 为什么我会盯上这个压缩包里的请假系统
一位刚做完课设的同学在群里发来一个压缩包,点名问“这套学生请假系统能不能直接跑”。我解压看了下,里面是四个 Python 文件加一个 qingjia.sql,文件数不多,结构却比很多“教育管理系统”项目清爽得多。最吸引我的是vacate.py这个命名——请假逻辑被单独拆成了一个模块,而不是全塞进主程序,对于要拿源码做二次开发的人来说,这种边界比花哨界面值钱得多。这个系统解决的是很具体的痛点:学生不用再跑办公室填纸质单,教师在线审批,管理员能拿到请假统计台账。它适合三类人:课程设计需要一套能现场演示的项目、刚学完 Python 和 MySQL 想练手整合、又或者是想把班级请假流程快速数字化的学生干部。代码不重,依赖少,按下面的步骤走,一两个小时能把整套流程跑通。
2. 模块拆解与数据模型:这么小的系统为什么能撑住请假流程
很多人一拿到源码就急着双击运行,结果不是缺库就是报错,然后回头怪项目有问题。其实这类小系统的核心不在代码量,而在模块边界和数据表设计。先把包里的几个文件职责看清楚,后面改起来才有下手点。
2.1 按文件命名识别模块职责
这个压缩包的解压结果大致是这样的:
| 文件 | 命名意图 | 在流程中的位置 |
|---|---|---|
Student.py | 学生端主入口 | 登录后的菜单与请求分发 |
Stud.py | 可能是学生端的另一版本 | 与Student.py并存,用于对比或角色区分 |
vacate.py | 请假业务主体 | 请假单的新增、状态变更、查询 |
tech.py | 工具与技术支撑 | 数据库连接、日期格式处理、公共函数 |
daba.py | 统计或扩展模块 | 请假数据汇总、排名、导出 |
__pycache__ | 已编译的字节码 | 不参与业务逻辑,删除不影响运行 |
从命名习惯推测,Student.py和Stud.py大概率是同一角色的两个入口或两种菜单布局;tech.py是公共层,所有数据库操作都从这里走;vacate.py是核心业务层;daba.py承担统计职责。这个分层思路和 Spring Boot 里的 Controller/Service/DAO 是同一套逻辑,只是用 Python 脚本的方式表达了出来。
我一般拿到这种压缩包,会先搜索import vacate和from tech import,把调用关系画出来。这几步能帮你快速定位:谁调了谁、哪个文件是入口、哪个文件只是被动工具。很多同学一上来就找大段注释,反而被非核心代码带偏。
2.2 qingjia.sql 里的表结构与请假状态机
数据库脚本是这套系统的地基。请假审批不是一条数据从头写到尾那么简单,它至少要经历“提交 → 审批 → 销假”三个阶段,而每一阶段的状态变化都落在数据库里。
从脚本内容和常见设计模式看,qingjia.sql里大概率包含了三类核心表:
| 表 | 角色 | 关键字段 |
|---|---|---|
student | 学生信息 | ID、姓名、班级、学号、密码 |
teacher或user | 教师/审批人 | ID、姓名、角色权限 |
leave_request | 请假单主表 | 请假编号、学生ID、事由、开始日期、结束日期、状态、审批人 |
approval_log | 审批记录表 | 请假编号、审批人、审批时间、意见、动作 |
请假状态机是整个系统的灵魂。最常见的设计是:
待审批 -> 已批准 -> 已销假 -> 已驳回 (终止)为什么状态不能只用一个字段“是/否”?因为审批流程里存在撤回、驳回、销假等多个动作。只用布尔值,你无法回答“这个假是谁批的”“为什么被驳回”。approval_log表的意义就在这:每次状态变更都追加一条记录,而不是覆盖原数据。这也为后面多级审批的扩展留了后路——你只需要按顺序追加审批节点,不需要动主表结构。
如果你在源码里看到update leave_request set status = ...这样的语句,说明它确实跑在状态机上;如果只有insert和delete,那大概率只是玩具级 CRUD。
2.3 权限边界为什么必须放在入口处
学生、教师、管理员这三种角色的操作差异极大。学生能提交请假单,教师能审批,管理员能看统计。这套系统的权限控制不会复杂到做 Spring Security 那种拦截器,最合理的做法是在入口菜单上做分流。
常见做法是在Student.py或Stud.py里先读取登录角色,再渲染对应的菜单:
# 伪代码示意,实际函数名以源码为准 role = get_current_role(user_id) if role == 'student': show_menu(['提交请假', '我的记录', '撤回申请']) elif role == 'teacher': show_menu(['待审批列表', '班级请假统计']) elif role == 'admin': show_menu(['全部记录', '请假率统计', '导出报表'])这段代码逻辑上很直白,但这里恰恰是新手最容易埋雷的地方:权限判断如果只写在界面菜单里,而接口层没有二次校验,别人完全可以绕过菜单直接调用数据操作函数。好在课设级别系统大多是单机内网运行,威胁面小。若真要上公网,建议在tech.py的数据库操作层统一加角色校验,而不是在界面层做。
3. 本地部署与首次运行:把 Python+MySQL 版本跑通的完整路径
对这类源码包,我不喜欢一上来就讲业务功能,因为跑不通的功能全是纸上谈兵。这一章按“环境 → 数据库 → 启动 → 自测”的顺序走,每一步都给出可复制命令和参数说明。
3.1 环境准备:Python 版本、依赖库与 MySQL 服务
这个项目依赖不重,核心就是 Python 访问 MySQL 的驱动。根据文件后缀和项目年代推断,它大概率用PyMySQL(如果直接import MySQLdb则是老驱动,下面第 4 章会讲解决办法)。先把基础环境配齐:
# 检查Python版本,建议3.x python --version # 安装MySQL连接驱动 pip install pymysql # 检查MySQL服务是否运行 mysql --version参数说明:pip install pymysql安装的是纯 Python 实现的驱动,不用编译,兼容性好;如果你的机器上同时装了 Python 2 和 3,需要用pip3而不是pip。MySQL 版本建议是 5.7 或更高,8.0 也可以,但身份认证插件需要额外处理(见第 4 章)。
安装完成后,可以用一行命令验证驱动能不能正常导入:
python -c "import pymysql; print(pymysql.__version__)"如果输出版本号,说明依赖到位。这一步虽然简单,却能帮你区分“环境问题”和“代码问题”,后面排查能省一半时间。
3.2 初始化数据库:导入 qingjia.sql 与连接配置
数据库这块要特别小心编码问题。导入脚本前,先切到脚本所在目录,然后执行:
mysql -u root -p --default-character-set=utf8mb4 < qingjia.sql--default-character-set=utf8mb4这个参数不是可选项。很多人的中文请假事由导入后变成???,就是因为没指定字符集,客户端用了默认的latin1去解析 UTF-8 的中文内容。utf8mb4比utf8更强的点在于它能存表情符号和生僻字,对请假事由这种自由文本来说更稳妥。
导入完成后,进 MySQL 确认表是否创建成功:
mysql -u root -p USE qingjia; SHOW TABLES; SELECT COUNT(*) FROM student;如果SHOW TABLES能看到表,SELECT能查出行数,说明数据库初始化成功。注意USE qingjia;里的库名要与脚本里的CREATE DATABASE语句保持一致,如果脚本里没有建库语句,你需要手动先建一个库再导入。
接下来是连接配置。在tech.py里,通常会有类似这样的参数区:
DB_CONFIG = { 'host': 'localhost', 'port': 3306, 'user': 'root', 'password': 'your_password', 'database': 'qingjia', 'charset': 'utf8mb4' }这里唯一要改的是password字段。如果你是空密码,就留空字符串,但我不建议在生产环境这么做。修改后不要急着跑,先写一个三行脚本测试连接:
import pymysql conn = pymysql.connect( host='localhost', user='root', password='your_password', database='qingjia', charset='utf8mb4' ) print('数据库连接成功') conn.close()如果这里报错,先检查 MySQL 服务有没有启动,再看密码和端口是否正确。port默认是 3306,除非你手动改过。
3.3 启动主程序与全流程自测
数据库通了,现在启动主程序。按照入口推断,学生端入口是Student.py,运行方式很简单:
python Student.py如果你不确定哪个文件是入口,可以用一个高性价比的办法快速判断:直接运行每个文件,看哪个文件会弹出交互菜单而不是报“缺少main”之类的错误。运行后你在终端里应该能看到类似这样的菜单:
1. 提交请假 2. 查看我的记录 3. 撤回申请 4. 退出全流程自测建议按这条路线走:
- 先用
student表里的一个学生账号登录 - 提交一条请假申请,事由填中文,起止日期选择明天到后天
- 退出学生端,用教师账号登录,找到待审批列表
- 执行批准操作
- 再用学生账号登录,查看记录,确认状态是否是“已批准”
这个过程覆盖了“新增 → 查询 → 审批 → 回显”四个核心动作。如果你能把这四个动作完整跑通,这台部署基本就稳了。跑不通也不要急着改代码,先记录报错信息,然后对照第 4 章的排查手册逐条排除。
4. 避坑排查:刚上手最容易翻车的五件事
这类课设源码包的特点是“作者跑得通,换一台机器就玄学”。结合我这几年拆包的经验,下面五条是踩中频率最高的坑。每条都按“现象 → 原因 → 解决”来讲。
4.1 报错 ModuleNotFoundError: MySQLdb
现象:运行python Student.py后,终端直接抛出ModuleNotFoundError: No module named 'MySQLdb'。
原因:源码里写的是import MySQLdb,这是 Python 2 时代的 MySQL 驱动,在 Python 3 环境里默认没有安装,而且这个库本身对 Python 3 的支持很弱,直接pip install mysql-python大概率编译失败。
解决:不要硬刚老驱动,在tech.py的顶部加两行兼容代码:
import pymysql pymysql.install_as_MySQLdb()install_as_MySQLdb()的作用是把pymysql伪装成MySQLdb,让旧代码里的import MySQLdb能直接通过。这种方式比逐个替换 import 语句要快得多,而且不会破坏原有代码结构。加完之后重新运行,如果还报错,检查pymysql是否安装成功。
4.2 导入 SQL 后中文全变问号
现象:执行完mysql -u root -p < qingjia.sql后,进入 MySQL 查询,发现表里的中文全是???。
原因:导入数据时,客户端和服务器之间的字符集没有对齐。MySQL 默认字符集可能是latin1,而脚本文件是 UTF-8 编码。这种错位在导入阶段不报错,数据入库后已经损坏,删了重导是唯一出路。
解决:删除数据库,重新以指定字符集导入。顺序不能乱:
DROP DATABASE IF EXISTS qingjia; CREATE DATABASE qingjia DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE qingjia; SOURCE qingjia.sql;或者更便捷的一条命令:
mysql -u root -p --default-character-set=utf8mb4 qingjia < qingjia.sql导入后马上执行SELECT * FROM student LIMIT 2;验证中文字段是否正常。如果还是乱码,用编辑器把qingjia.sql转成 UTF-8 无 BOM 格式再导一次。
4.3 启动后窗口一闪而过
现象:在 Windows 下双击Student.py或者双击 .bat 文件,窗口一闪就消失了,根本来不及看错误信息。
原因:运行时报错后程序直接退出,而你的打开方式没有提供停留查看错误的机会。这不是源码问题,是运行方式问题。
解决:不要双击,改用命令行运行。按Win + R输入cmd,在命令行中切换到源码目录,再执行:
python Student.py如果报错,错误信息会停留在命令行窗口里。如果你一定要双击运行,可以把启动命令写进一个run.bat,并在末尾加pause:
@echo off python Student.py pausepause的作用是让窗口在执行结束后等待按键,这样即使出错也能看到报错内容。下次操作课设项目前先看错误信息,能少走很多弯路。
4.4 连接 MySQL 8.0 报身份认证错误
现象:MySQL 连接报Authentication plugin 'caching_sha2_password' cannot be loaded。
原因:MySQL 8.0 默认身份认证插件从mysql_native_password换成了caching_sha2_password,而你用的 PyMySQL 版本较旧,或者你连接时没有指定加密方式。
解决:方案有两种,选一个执行即可。方案一是升级 PyMySQL:
pip install --upgrade pymysql方案二是把 MySQL 用户改回旧认证方式:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;注意,FLUSH PRIVILEGES;必须执行,否则修改不会生效。改完之后,用前面第 3.2 节的测试脚本重连一次,看到“连接成功”再继续跑业务代码。
4.5 学生端和教师端权限串台
现象:用学生账号登录,菜单里居然出现了审批功能;或者用教师账号登录,却看不到待审批列表。
原因:入口文件没有根据登录角色正确分发菜单,或者角色判断依赖了硬编码的默认值。常见场景是Stud.py和Student.py两个文件里写死了不同角色的入口,但调用数据库查询角色时没有刷新当前登录用户。
解决:先检查登录后的用户 ID 是怎么传递的。我一般会在入口文件里加一个调试输出,确认当前角色读到的值:
print("当前登录用户ID:", user_id) print("当前登录角色:", role)如果发现 role 一直不变,重点排查tech.py里的get_current_role()函数,看它是不是用了全局变量缓存了第一次登录的值。改成每次从会话或参数里重新读取即可。另外,角色判断最好做“名单式校验”而不是“排除式校验”。
5. 改造升级:在源码上做多级审批与统计报表
跑通只是起点。很多人拿这套系统不是为了应付演示,而是真想用在班级或实验室里,那就会碰上两个绕不开的需求:多级审批和统计分析。这一章给出可执行的改法。
5.1 把单级审批改成多级审批状态机
原系统的审批流程是“学生提交 → 教师审批”。但在真实场景里,往往是“班主任初审 → 辅导员终审 → 教务处备案”,每一级都要留痕。改法并不复杂,前提是你得把状态字段从字符串升级成带顺序的整型,或者在一个状态枚举上做映射。
常见做法是在leave_request表里增加approval_level字段:
ALTER TABLE leave_request ADD COLUMN approval_level INT DEFAULT 1 COMMENT '当前审批层级';然后在vacate.py中把审批逻辑改成顺序递进:
approval_levels = [ ('pending_class', '班主任初审'), ('pending_counselor', '辅导员终审'), ('approved', '已批准') ] def approve(leave_id, current_user): leave = get_leave_by_id(leave_id) current_level = leave['approval_level'] if current_level >= len(approval_levels) - 1: update_status(leave_id, 'approved') else: new_level = current_level + 1 update_level(leave_id, new_level) log_approval(leave_id, current_user, '通过,进入下一级') notify_followers(leave_id, approval_levels[new_level]['name'])这段代码的核心是用approval_level充当状态机指针,approve()每执行一次指针就加一,到终点才把状态置为approved。注意,修改后原有查询逻辑也要同步调整:学生的“我的记录”里,状态不能只看status字段,而要结合approval_level才能显示“审核中(第2/3级)”之类的中途状态。
5.2 把终端提示换成真实通知
原系统的“通知提醒”很可能只是控制台打印一行文字,这在演示场景还行,实际使用时根本没人盯着终端看。要把它改造成有用通知,最简单又不引入新依赖的方式是发邮件。
先在tech.py里加一个发送函数:
import smtplib from email.mime.text import MIMEText def send_email(to_addr, subject, content): smtp_server = 'smtp.example.com' smtp_user = 'sender@example.com' smtp_pass = 'your_auth_code' msg = MIMEText(content, 'plain', 'utf-8') msg['Subject'] = subject with smtplib.SMTP_SSL(smtp_server, 465) as server: server.login(smtp_user, smtp_pass) server.send_message(msg, from_addr=smtp_user, to_addrs=to_addr)参数说明:SMTP_SSL适用于 465 端口;如果你的邮箱服务商用的是 587 端口,则需要改成SMTP加starttls()。密码位置填的是授权码而不是邮箱登录密码,这一点别搞混,不然会一直 535 认证失败。
然后在审批动作里调用:
send_email(student_email, '请假审批结果', f'你的请假单已批准,时长{leave_days}天')改完这步,系统才算从“能演示”变成“能用”。
5.3 从 daba.py 出发做出出勤台账导出
daba.py如果已经写了统计函数,那就是个宝库。没写也不怕,直接用 SQL 也能把核心指标捞出来。
我常用的统计 SQL 是这三条:
-- 班级请假率:某班在某时间段内请假人次 / 全班人数 SELECT COUNT(*) AS leave_times FROM leave_request WHERE class_id = '2023-01' AND start_date BETWEEN '2025-01-01' AND '2025-06-30'; -- 个人请假次数排行 SELECT student_id, COUNT(*) AS cnt FROM leave_request WHERE status = 'approved' GROUP BY student_id ORDER BY cnt DESC LIMIT 10;在daba.py里把查询结果写到 Excel 或 CSV,可以在 Python 端用标准库直接生成:
import csv def export_to_csv(rows, filename): with open(filename, 'w', newline='', encoding='utf-8-sig') as f: writer = csv.writer(f) writer.writerow(['学生ID', '请假次数']) writer.writerows(rows)注意编码这里用的是utf-8-sig而不是utf-8。因为 Excel 打开 CSV 时默认按 GBK 或 ANSI 解析,直接写 UTF-8 会产生乱码。utf-8-sig带 BOM 头,Excel 能正确识别。这个细节非常影响观感。
6. 上线前要做的验证:造数据、压时间边界与数据一致性
系统改完了,先别急着给同学用,按我的习惯,这份清单至少要过一遍。
第一,造数据测并发边界。用脚本插入 200 条请假记录,模拟一个月的数据量,然后反复提交请假、审批、撤回,看有没有报错。课设级系统在 200 条数据范围内出问题的概率不大,但你能借此验证 SQL 语句是否漏了索引,尤其是leave_request表上的student_id和status字段。
第二,压时间边界。查一下vacate.py里日期处理的写法,重点看“结束日期早于开始日期”这类非法输入有没有被拦截。常见的翻车场景是:学生提交了一个已经结束的请假单,系统照样生成title并通过审批。正确的做法是在提交时做一次校验:
if end_date < start_date: raise ValueError('结束日期不能早于开始日期')第三,验证数据一致性。我把状态机和审批日志连起来测:把所有已批准的单子导出来,逐一核对approval_log表里有没有对应的审核记录。一对不上就说明写入逻辑有遗漏,这个检查最好写成脚本自动跑,而不是肉眼比对。
def check_consistency(): sql = """ SELECT lr.id, COUNT(al.id) AS log_cnt FROM leave_request lr LEFT JOIN approval_log al ON lr.id = al.leave_id WHERE lr.status = 'approved' GROUP BY lr.id HAVING COUNT(al.id) < 1 """ rows = query(sql) if rows: print(f'发现{len(rows)}条已批准但没有审批记录的数据')有趣的是,这类问题往往不是出现在核心流程,而是出现在“撤回后重新提交”这种边缘操作上。旧数据没有被清理,新数据又插入,导致统计翻倍。
也是折腾这套系统之后,我养成了个习惯:所有课设源码拿到手,第一件事永远不是看功能文档,而是把异常输入、跨日边界、并发重复提交这几类刁钻情况先测一遍。这套验证思维,比源码本身值钱得多。希望帮到你。
本文还有配套的精品资源,点击获取