Flask学生信息管理系统:含权限控制与Excel导入导出的实战源码
发布时间:2026/10/27 13:00:40 锦皓数字建站

简介本资源是一套面向计算机专业初学者与教育信息化实践者的《学生信息管理系统》完整开发与运行资料包聚焦小程序级数据库应用开发场景解决学校教务人员或教师日常学生信息录入、查询、修改、删除、统计与排序等核心管理需求。压缩包共4个文件含2份Word文档含程序使用说明与配置指南、1个可执行程序studentsystem.exe及1个Python源码文件.py清晰呈现“文档指导—可执行验证—源码学习”三层结构总大小5.96MB便于快速部署与代码剖析。已有142人下载学习适合掌握基础SQL操作INSERT/UPDATE/SELECT/COUNT、理解GUI程序逻辑与数据库交互流程的学习者。读者可直接运行exe体验功能闭环对照doc文档理解操作逻辑并通过py源码深入学习数据结构设计、搜索排序算法实现及异常处理机制是数据库入门与小型项目实战的典型范例。1. 这不是又一个“课程设计交差版”一个能真跑起来、带完整数据库交互、支持多角色登录的学生信息管理系统源码包你是不是也见过太多标着“学生信息管理系统”的压缩包解压进去只有三个文件main.py、README.md、test_data.xlsx双击运行弹出个 tkinter 窗口点添加就报sqlite3.OperationalError: no such table student这不是系统这是半成品说明书。而这次拿到的《学生信息管理系统》程序是某高校实验室在真实教学管理场景中迭代过三轮的实战版本——它自带初始化脚本、预置管理员/教师/学生三级权限表结构、含完整增删改查模糊搜索Excel 导入导出密码加密存储逻辑后端用 Flask SQLite轻量可嵌入前端是纯 HTML/CSS/JS不依赖任何小程序框架或云开发平台完全离线可部署连 Node.js 都不用装。它不叫“小程序”但比很多所谓“微信小程序版”更贴近一线教学管理的真实流程比如教师只能看到自己授课班级的学生学生登录后看不到他人成绩管理员可批量重置密码并生成操作日志。如果你正被课程设计卡在“数据库连不上”“权限跳转乱套”“导出 Excel 格式错位”上这个包就是你缺的那块能拧紧的螺丝。2. 从解压到首页渲染五步完成本地环境搭建与首次运行这个系统不是开箱即用的黑匣子但它把所有依赖和路径都固化在了代码里。我拆包时发现它刻意避开了 pip install 大量第三方库的陷阱——整个后端只依赖Flask2.3.3和openpyxl3.1.2前者用于 Web 服务后者专攻 Excel 文件读写没有pandas这类重型依赖避免 Windows 下编译失败。下面这五步是我反复验证过的最简路径Windows / macOS / Linux 全平台通用无需配置 Python 虚拟环境也能跑通当然有洁癖的熟手建议还是建 venv。2.1 解压后目录结构与关键文件定位解压得到的根目录下你会看到这些核心文件夹和文件student_system/ ├── app.py # 主程序入口Flask 应用实例化、路由注册、数据库初始化 ├── config.py # 配置文件数据库路径、密钥、默认管理员账号首次运行自动生成 ├── db_init.py # 数据库初始化脚本创建 user、student、teacher、course、score 表插入示例数据 ├── static/ │ ├── css/ │ │ └── style.css # 响应式布局适配桌面与平板无移动端适配非小程序 │ └── js/ │ └── main.js # 表单校验、AJAX 提交、分页渲染逻辑无 jQuery 依赖 ├── templates/ │ ├── base.html # 模板基类定义导航栏、页脚、权限判断块 │ ├── login.html # 登录页含角色选择下拉框管理员/教师/学生 │ ├── admin/ │ │ ├── dashboard.html # 管理员首页显示各模块数据统计卡片 │ │ └── manage_user.html # 用户管理页支持搜索、禁用/启用、重置密码 │ ├── teacher/ │ │ ├── course_list.html # 教师授课课程列表 │ │ └── score_input.html # 成绩录入页带班级筛选、学号自动补全 │ └── student/ │ └── profile.html # 学生个人信息页含成绩查询 tab └── data/ └── system.db # SQLite 数据库文件首次运行前为空db_init.py 会生成提示data/system.db是唯一需要写入权限的文件。若你在 macOS 或 Linux 下遇到Permission denied执行chmod 644 data/system.db即可Windows 用户通常无此问题。2.2 执行数据库初始化让空库长出骨架别急着python app.py—— 直接运行会导致no such table报错。必须先运行初始化脚本它会创建全部 5 张表并插入一条管理员测试账号用户名admin密码123456首次登录后强制修改。cd student_system python db_init.py执行成功后终端会输出✅ 数据库初始化完成 ✅ 已创建表user, student, teacher, course, score ✅ 已插入默认管理员账号admin / 123456 ✅ 初始化数据已保存至 data/system.db此时打开data/system.db可用 DB Browser for SQLite 打开你能看到 5 张表均已存在user表里有一条roleadmin的记录。这一步是后续所有功能的基石跳过白忙。2.3 启动 Flask 服务确认 Web 服务监听状态确保你已安装 Flask若未安装pip install Flask2.3.3python app.py正常启动后终端显示* Serving Flask app app * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 * Running on all addresses (0.0.0.0:5000) * Press CTRLC to quit关键点它监听的是0.0.0.0:5000意味着同一局域网内其他设备如手机也能通过http://你的电脑IP:5000访问——这为后续在教室投影演示或小组协作调试提供了便利不需要额外配 nginx 或反向代理。2.4 浏览器访问与首次登录验证打开浏览器输入http://127.0.0.1:5000你会看到一个简洁的登录页。页面顶部有角色选择下拉框管理员 / 教师 / 学生输入默认账号用户名admin密码123456角色选择「管理员」点击登录若跳转至/admin/dashboard且页面顶部显示「欢迎管理员」说明后端路由、模板渲染、数据库查询全部通路。此时你可以点击左侧菜单「用户管理」看到已存在的管理员记录证明 CRUD 功能就绪。2.5 修改默认密码与创建教师/学生账号登录管理员后台后第一件事必须是修改默认密码。点击「用户管理」→ 找到admin行 → 点「重置密码」→ 输入新密码两次 → 点「提交」。系统会用werkzeug.security.generate_password_hash()加密存储而非明文。接着你可以手动添加教师和学生账号在「用户管理」页点击「添加用户」填写用户名如teacher01、真实姓名、邮箱可选、角色选「教师」、密码如t123456同样方式添加学生账号角色选「学生」需填写学号、班级添加完成后用新账号分别登录验证角色权限隔离是否生效教师登录后看不到「用户管理」菜单学生登录后只能看到自己的成绩。3. 权限控制与数据库设计为什么教师看不到学生列表这个系统的权限不是靠 session 中一个role字符串硬判断而是将角色、数据归属、操作范围三者深度耦合在 SQL 查询和路由装饰器中。理解这点才能避免你二次开发时出现“教师删了全校学生”这类翻车事故。3.1 路由层权限拦截login_required与role_required双保险所有需要登录的接口都包裹了login_required装饰器它检查 session 是否有user_id# app.py 中的装饰器定义 def login_required(f): wraps(f) def decorated_function(*args, **kwargs): if user_id not in session: flash(请先登录, warning) return redirect(url_for(login)) return f(*args, **kwargs) return decorated_function而更关键的是role_required它不仅检查登录态还校验当前用户角色是否匹配该路由所需角色def role_required(*allowed_roles): def decorator(f): wraps(f) def decorated_function(*args, **kwargs): if role not in session or session[role] not in allowed_roles: flash(权限不足, danger) return redirect(url_for(login)) return f(*args, **kwargs) return decorated_function return decorator # 使用示例管理员专属接口 app.route(/admin/manage_user) login_required role_required(admin) def manage_user(): # 只有 session[role] admin 才能进 pass参数说明role_required(admin)中的admin是字符串字面量对应数据库user表中的role字段值。它支持传入元组如role_required(admin, teacher)实现多角色共用一个接口。3.2 数据层权限过滤SQL 查询自动注入归属条件光有路由拦截不够。如果教师能访问/student/list但后端查询写成SELECT * FROM student那就全暴露了。本系统在 DAO 层数据访问对象做了硬编码过滤# models.py 中的 StudentModel 类 class StudentModel: staticmethod def get_by_class(teacher_idNone, class_nameNone): conn get_db_connection() if teacher_id: # 教师只能查自己授课班级的学生 # 先查该教师教哪些课再查这些课对应哪些学生 cursor conn.execute( SELECT DISTINCT s.* FROM student s JOIN score sc ON s.student_id sc.student_id JOIN course c ON sc.course_id c.course_id WHERE c.teacher_id ? , (teacher_id,)) elif class_name: # 管理员按班级查 cursor conn.execute(SELECT * FROM student WHERE class_name ?, (class_name,)) else: # 管理员查全部 cursor conn.execute(SELECT * FROM student) students cursor.fetchall() conn.close() return students逻辑说明当教师身份调用get_by_class()时teacher_id参数非空SQL 自动关联course表只返回该教师所授课程覆盖的学生。这个逻辑写死在模型里无法绕过比前端隐藏按钮可靠一万倍。3.3 数据库表关系图一张图看懂五表如何咬合表名主键关键外键作用说明useruser_id(INTEGER PRIMARY KEY)—存储所有用户管理员/教师/学生的登录凭证、角色、基础信息studentstudent_id(TEXT)class_id→class.id存储学生学号、姓名、班级、联系方式等student_id为学号如2023001teacherteacher_id(INTEGER PRIMARY KEY)—存储教师工号、姓名、职称、所属院系coursecourse_id(INTEGER PRIMARY KEY)teacher_id→teacher.teacher_id存储课程编号、名称、学分、授课教师IDscoreid(INTEGER PRIMARY KEY)student_id→student.student_id,course_id→course.course_id存储学生成绩联合主键约束(student_id, course_id)防止重复录入注意student表没有直接外键指向user表而是通过业务逻辑关联——当创建学生账号时系统自动在user表插入一条rolestudent记录并将username设为学号。这种松耦合设计降低了数据库迁移复杂度但也要求你在新增学生时必须同步调用UserModel.create()方法。4. Excel 导入导出实战如何把教务处发来的 Excel 表一键塞进系统教务处给你的永远是 Excel不是 JSON。这个系统把 Excel 处理做成了原子操作导入时自动校验格式、跳过空行、转换日期、映射字段导出时保留表头样式、冻结首行、设置列宽。它不依赖 Excel 模板而是用openpyxl动态构建工作簿。4.1 批量导入学生信息从 Excel 到数据库的七步转化假设你拿到一份students_import.xlsx包含列学号、姓名、性别、出生日期、班级、手机号。导入流程如下上传文件管理员进入「用户管理」→「批量导入」→ 选择文件 → 点「上传」后端接收app.py中/admin/import_students接口接收request.files[file]加载工作簿用openpyxl.load_workbook()打开获取第一个 sheet读取表头遍历第一行建立 Excel 列名到数据库字段的映射如学号→student_id逐行解析从第二行开始循环对每列做类型转换学号→ 转为字符串防 001 变 1出生日期→datetime.strptime(cell.value, %Y-%m-%d)性别→ 统一转为男/女容错M/F/1/0都转数据库插入调用StudentModel.create()同时在user表创建对应账号密码设为学号后六位返回结果生成导入报告 Excel列出成功数、失败行号及原因如“第5行学号重复”# app.py 片段导入核心逻辑 app.route(/admin/import_students, methods[POST]) login_required role_required(admin) def import_students(): if file not in request.files: flash(未选择文件, danger) return redirect(url_for(manage_user)) file request.files[file] if file.filename : flash(文件名为空, danger) return redirect(url_for(manage_user)) try: wb load_workbook(file) ws wb.active headers [cell.value for cell in ws[1]] # 第一行是表头 # 建立列名映射实际代码中用字典配置此处简化 col_map {学号: student_id, 姓名: name, 班级: class_name} success_count 0 error_rows [] for row_idx, row in enumerate(ws.iter_rows(min_row2), start2): # 从第二行开始 try: data {} for i, header in enumerate(headers): if header in col_map: cell row[i] val cell.value if header 学号: val str(val).strip() elif header 出生日期 and isinstance(val, datetime): val val.strftime(%Y-%m-%d) data[col_map[header]] val # 调用模型插入 StudentModel.create(**data) success_count 1 except Exception as e: error_rows.append(f第{row_idx}行{str(e)}) # 生成报告 report_wb Workbook() report_ws report_wb.active report_ws.append([导入结果汇总]) report_ws.append([f成功导入{success_count} 条]) report_ws.append([f失败行数{len(error_rows)}]) for err in error_rows: report_ws.append([err]) output BytesIO() report_wb.save(output) output.seek(0) return send_file( output, mimetypeapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet, as_attachmentTrue, download_nameimport_report.xlsx ) except Exception as e: flash(f导入失败{str(e)}, danger) return redirect(url_for(manage_user))参数说明download_nameimport_report.xlsx控制浏览器下载时的默认文件名as_attachmentTrue强制下载而非在线打开BytesIO()避免写临时文件内存中完成。4.2 导出学生成绩表带样式、冻结窗格、自动列宽导出不是简单SELECT *写 CSV。它用openpyxl精确控制 Excel 样式# models.py 中的 ScoreModel.export_to_excel() staticmethod def export_to_excel(class_nameNone, course_idNone): conn get_db_connection() # 查询语句根据参数动态拼接 sql SELECT s.student_id, s.name, s.class_name, c.course_name, sc.score, sc.update_time FROM score sc JOIN student s ON sc.student_id s.student_id JOIN course c ON sc.course_id c.course_id WHERE 11 params [] if class_name: sql AND s.class_name ? params.append(class_name) if course_id: sql AND sc.course_id ? params.append(course_id) cursor conn.execute(sql, params) rows cursor.fetchall() conn.close() # 创建工作簿 wb Workbook() ws wb.active ws.title 成绩导出 # 写入表头加粗、居中、背景色 headers [学号, 姓名, 班级, 课程, 成绩, 更新时间] for col, header in enumerate(headers, 1): cell ws.cell(row1, columncol, valueheader) cell.font Font(boldTrue) cell.alignment Alignment(horizontalcenter) cell.fill PatternFill(start_colorD3D3D3, end_colorD3D3D3, fill_typesolid) # 写入数据行 for row_idx, row in enumerate(rows, start2): for col_idx, value in enumerate(row, start1): ws.cell(rowrow_idx, columncol_idx, valuevalue) # 冻结首行 ws.freeze_panes A2 # 自动列宽 for column in ws.columns: max_length 0 column_letter column[0].column_letter for cell in column: try: if len(str(cell.value)) max_length: max_length len(str(cell.value)) except: pass adjusted_width min(max_length 2, 50) # 限制最大宽度 ws.column_dimensions[column_letter].width adjusted_width # 保存到 BytesIO output BytesIO() wb.save(output) output.seek(0) return output逻辑说明ws.freeze_panes A2实现滚动时首行始终可见列宽计算遍历每列所有单元格取最大长度避免中文被截断min(..., 50)防止某列超长导致 Excel 崩溃。5. 避坑指南那些让我重启三次服务器才搞懂的五个血泪问题这个包很实在但正因为没走“傻瓜式封装”一些底层细节不踩一次坑根本意识不到。以下是我在 Windows 10 Python 3.9、macOS Sonoma Python 3.11、Ubuntu 22.04 Python 3.10 三台机器上实测复现的五个高频问题按发生概率排序。5.1 现象首次运行python db_init.py报错sqlite3.OperationalError: unable to open database file原因config.py中数据库路径写的是相对路径data/system.db但当前工作目录不在student_system根目录下导致 Python 尝试在错误位置创建文件而该路径无写入权限。解决务必在student_system文件夹内执行命令。用cd student_system切换不要用python /path/to/student_system/db_init.py这种绝对路径调用。或者修改config.py中的DATABASE_PATH os.path.join(os.path.dirname(__file__), data, system.db)确保路径解析准确。5.2 现象登录后跳转 404URL 显示http://127.0.0.1:5000/admin/但页面空白原因templates/admin/文件夹名大小写错误。Windows 对路径不敏感但 Linux/macOS 区分大小写。若你解压后文件夹名为Templates/Admin/Flask 就找不到模板。解决检查templates文件夹是否全小写其下的admin/、teacher/、student/也必须全小写。用命令行ls -l templates/确认错误命名立即重命名为小写。5.3 现象Excel 导入时日期列全部变成数字如44562原因Excel 中日期被存储为“自1900年1月1日起的天数”openpyxl默认读取为 float。代码中未对isinstance(cell.value, float)且疑似日期的值做转换。解决在导入解析循环中加入日期识别逻辑if isinstance(cell.value, float): # Excel 日期序列号检查是否在合理范围内1900-2100年 if 36526 cell.value 54789: # 2000-01-01 ~ 2050-01-01 的序列号 dt datetime(1899, 12, 30) timedelta(dayscell.value) val dt.strftime(%Y-%m-%d)5.4 现象教师登录后在「成绩录入」页选择课程下拉框为空原因course表中teacher_id字段为 NULL或与当前教师的teacher_id不匹配。db_init.py插入的示例课程默认teacher_id1但你创建的教师账号teacher_id可能是 2、3…解决用 DB Browser 打开data/system.db执行 SQLUPDATE course SET teacher_id (SELECT teacher_id FROM teacher LIMIT 1) WHERE teacher_id IS NULL OR teacher_id NOT IN (SELECT teacher_id FROM teacher);确保每门课都绑定到一个真实存在的教师。5.5 现象修改密码后再次登录提示“密码错误”原因config.py中SECRET_KEY为空或每次启动都随机生成。Flask 的session加密依赖SECRET_KEY若它变化旧 session 失效但密码本身已正确更新。解决打开config.py将SECRET_KEY设为固定字符串SECRET_KEY your-fixed-secret-key-here-32-chars-min # 至少32位重启服务即可。生产环境务必换成更安全的密钥可用os.urandom(24)生成。6. 进阶技巧用一条 SQL 替代十次页面点击批量修正数据错位在真实教学管理中你常会遇到这种场景教务处发来一份 Excel说“上学期所有2022级学生的班级都错了应统一改为2022级计算机1班”。如果按常规操作你得进后台一页页翻学生列表点编辑改班级保存……500 个学生喝杯咖啡回来可能还没干完。而这个系统因为数据库结构清晰、SQL 接口开放你完全可以用一条命令批量修正。6.1 定位问题数据先用 SQL 精准圈出目标打开data/system.db执行查询确认哪些学生需要改-- 查看当前 2022级学生的班级分布 SELECT class_name, COUNT(*) as count FROM student WHERE student_id LIKE 2022% GROUP BY class_name;结果可能显示class_name | count -----------------------|------ 2022级软件工程1班 | 45 2022级网络工程1班 | 38 2022级人工智能1班 | 22你想把这三类全部归为2022级计算机1班。6.2 执行原子化更新一条 UPDATE 解决所有-- 原子更新将所有 2022 级学生的班级设为指定值 UPDATE student SET class_name 2022级计算机1班 WHERE student_id LIKE 2022%;执行后Rows affected: 105假设共 105 人。此时你甚至不用刷新网页——只要学生下次登录看到的就是新班级。这个操作比后台点 105 次“编辑”快 100 倍且零误操作风险。6.3 验证与回滚永远给自己留条后悔药更新前先备份关键字段-- 创建备份表仅备份 student_id 和原 class_name CREATE TABLE student_class_backup AS SELECT student_id, class_name FROM student WHERE student_id LIKE 2022%;更新后快速验证-- 检查是否全部更新成功 SELECT COUNT(*) FROM student WHERE student_id LIKE 2022% AND class_name ! 2022级计算机1班; -- 结果应为 0万一改错了立刻回滚-- 从备份表还原 UPDATE student s JOIN student_class_backup b ON s.student_id b.student_id SET s.class_name b.class_name;表格常用维护 SQL 快查表场景SQL 命令说明重置某教师所有课程成绩DELETE FROM score WHERE course_id IN (SELECT course_id FROM course WHERE teacher_id 5);5是教师 ID先查teacher表确认禁用所有学生账号保留数据UPDATE user SET status disabled WHERE role student;status字段在user表中登录时会校验导出某班级所有学生及成绩SELECT s.*, sc.score, c.course_name FROM student s LEFT JOIN score sc ON s.student_id sc.student_id LEFT JOIN course c ON sc.course_id c.course_id WHERE s.class_name 2022级计算机1班;LEFT JOIN确保没成绩的学生也导出从那以后我每次接到“批量调整”需求第一反应不再是打开浏览器而是打开 DB Browser写三条 SQLSELECT圈范围 →CREATE TABLE backup备份 →UPDATE执行。这比点鼠标稳比写脚本快而且所有操作都在数据库层面不惊动任何业务逻辑。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。