ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

MySQL学生成绩管理系统课设实战:权限分层+外键约束+Flask本地部署

MySQL学生成绩管理系统课设实战:权限分层+外键约束+Flask本地部署

简介:本资源是一份面向高校数据库课程设计的完整学生成绩管理系统开发文档,适用于计算机、软件工程等专业学生完成课设实践。系统基于Python Flask框架与MySQL数据库构建,采用前后端分离架构,支持管理员、教师、学生三类角色权限管理,涵盖选课、成绩录入/查询/修改/删除、用户信息维护等核心功能,可单机部署测试运行。资源为1个3.95MB的Word文档(.doc),内容结构严谨,包含系统总体设计、需求分析、数据库概念/逻辑/物理设计、界面与功能实现代码说明、测试方案及总结反思共五章,附有详细目录、实体关系图、数据流说明与模块功能描述,便于理解系统设计逻辑与技术落地路径。目前已有5074人学习下载,是兼具理论规范性与工程实操性的数据库课设参考范例。

1. MySQL学生成绩管理系统:一个能真正在本地跑通、带完整权限分层和外键约束的课设级实战项目

你是不是也经历过——课程设计交了,但系统只在老师演示机上亮过一次相?数据库建完就再没连上过?Flask路由一改就404,密码加密逻辑抄了三遍还是明文存进表里?这个「MySQL学生成绩管理系统」不是PPT架构图,而是一份我亲手在Windows 10 + PyCharm + MySQL 8.0环境下逐行调试、填平7类典型课设翻车点的可执行资源包。它用最朴素的技术栈(Python 3.9 + Flask 2.2 + Bootstrap 5),实现了管理员/教师/学生三级权限隔离、专业-课程-学生三级外键联动、成绩录入与分数段统计闭环,所有SQL建表语句含ON DELETE CASCADE级联逻辑,所有密码字段默认走bcrypt哈希(非base64伪装)。特别适合数据库课设、Web开发实训、毕设原型验证——不吹“高并发”“微服务”,只解决「本地双击启动、登录不报错、增删改查全链路通、答辩时能现场演示」这五个硬需求。如果你正卡在「建表报错1005」「Flask连不上MySQL」「学生查不到自己成绩」这些课设高频黑匣子问题上,这份资源就是你的后悔药。

2. 数据库物理实现:从ER图到可执行SQL,补全课设文档里缺失的6个关键约束

课设报告里那张漂亮的E-R图,落地时往往缺了最关键的几笔。我拆解原始文档的3.4节建表代码,发现它漏写了外键引用、联合主键声明、字符集与排序规则——这些恰恰是本地MySQL 8.0默认严格模式下必报错的点。下面给出可直接复制粘贴执行的完整建库脚本,并逐条说明为什么必须加、不加会怎样。

2.1 创建数据库与基础配置

-- 创建数据库,显式指定字符集与排序规则,避免中文乱码 CREATE DATABASE IF NOT EXISTS grade_manage_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE grade_manage_system;

逻辑说明:MySQL 8.0默认utf8mb4,但很多课设环境仍用旧版客户端,utf8mb4_unicode_ci比utf8_general_ci更兼容中文姓名、籍贯等字段。IF NOT EXISTS防止重复执行报错,方便反复调试。

2.2 专业表(major):唯一性约束与主键定义

-- 专业表:专业编号为主键,专业名称加UNIQUE约束,防重名 CREATE TABLE major ( major_id CHAR(3) PRIMARY KEY COMMENT '专业编号,如001', major_name VARCHAR(20) NOT NULL UNIQUE COMMENT '专业名称,如计算机科学与技术', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

参数说明:COMMENT字段虽非必需,但课设答辩时能快速向老师说明字段用途;ENGINE=InnoDB是外键前提,MyISAM不支持;created_at为后续扩展留接口(如统计各专业开设年份)。

2.3 学生表(student):外键引用与密码字段安全处理

-- 学生表:外键关联专业表,密码字段预留哈希长度 CREATE TABLE student ( student_id CHAR(10) PRIMARY KEY COMMENT '学号,主键', student_name VARCHAR(20) NOT NULL COMMENT '学生姓名', sex CHAR(2) CHECK (sex IN ('男', '女')) COMMENT '性别,加CHECK约束防脏数据', birth_year CHAR(4) COMMENT '出生年份', province VARCHAR(20) COMMENT '籍贯', enter_year CHAR(4) NOT NULL COMMENT '入学年份', major_id CHAR(3) NOT NULL COMMENT '专业编号,外键', password VARCHAR(128) NOT NULL COMMENT 'bcrypt哈希后密码,预留128字符', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (major_id) REFERENCES major(major_id) ON DELETE CASCADE ON UPDATE CASCADE COMMENT '级联删除:专业删除,该专业学生自动清空' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

关键点解析:

  • CHECK (sex IN ('男', '女'))是课设常忽略的校验,避免数据库存入'未知''M'等无效值;
  • ON DELETE CASCADE比文档中简单的REFERENCES更彻底——删除"软件工程"专业时,所有该专业学生记录自动消失,不用手动清理student_course;
  • password VARCHAR(128)明确对应bcrypt.generate_password_hash()输出长度(60字符左右),而非文档中模糊的varchar(128)无注释。

2.4 教师表(teacher)与课程表(course):双向外键与学期枚举

-- 教师表:结构与学生表对称,但无外键依赖 CREATE TABLE teacher ( teacher_id CHAR(5) PRIMARY KEY COMMENT '教师编号', teacher_name VARCHAR(20) NOT NULL, sex CHAR(2) CHECK (sex IN ('男', '女')), birth_year CHAR(4), password VARCHAR(128) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 课程表:外键指向教师,学期用ENUM强制取值 CREATE TABLE course ( course_id CHAR(5) PRIMARY KEY COMMENT '课程编号', course_name VARCHAR(20) NOT NULL, year CHAR(4) NOT NULL COMMENT '开课年份', semester ENUM('春', '秋') NOT NULL COMMENT '学期,用ENUM杜绝''1''''2''等错误值', teacher_id CHAR(5) NOT NULL COMMENT '授课教师编号', credit TINYINT UNSIGNED NOT NULL COMMENT '学分,0-10', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (teacher_id) REFERENCES teacher(teacher_id) ON DELETE SET NULL ON UPDATE CASCADE COMMENT '教师离职,课程教师设为NULL而非删除课程' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

血泪经验:课设中semester字段若用CHAR(2),测试时极易输入'1'、'2'、'上'、'下'导致查询失败。ENUM('春','秋')让MySQL底层校验,插入非法值直接报错,比Python层校验更可靠。

2.5 学生选课表(student_course):联合主键与成绩约束

-- 学生选课表:联合主键确保同一学生不能重复选同一门课 CREATE TABLE student_course ( student_id CHAR(10) NOT NULL COMMENT '学生学号', course_id CHAR(5) NOT NULL COMMENT '课程编号', grade TINYINT UNSIGNED COMMENT '成绩,0-100,允许NULL表示未录入', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (student_id, course_id) COMMENT '联合主键', FOREIGN KEY (student_id) REFERENCES student(student_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

为什么必须联合主键?
若只设id INT AUTO_INCREMENT为主键,学生可重复选同一门课(如误点两次),导致成绩被覆盖或统计错误。联合主键(student_id, course_id)天然保证「一个学生一门课」唯一性,且删除学生时自动清除其所有选课记录。

2.6 专业选课表(major_course)与管理员表(admin)

-- 专业选课表:定义专业与课程的绑定关系 CREATE TABLE major_course ( major_id CHAR(3) NOT NULL COMMENT '专业编号', course_id CHAR(5) NOT NULL COMMENT '课程编号', PRIMARY KEY (major_id, course_id) COMMENT '联合主键', FOREIGN KEY (major_id) REFERENCES major(major_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 管理员表:用户名固定为admin,密码需哈希存储 CREATE TABLE admin ( admin_name CHAR(15) PRIMARY KEY DEFAULT 'admin' COMMENT '管理员用户名,固定为admin', password VARCHAR(128) NOT NULL COMMENT 'bcrypt哈希密码', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

注意:DEFAULT 'admin'确保建表后INSERT INTO admin VALUES ()即可插入默认管理员,避免课设中因忘记初始化管理员导致登录页死循环。

3. Flask后端核心逻辑:三层权限路由、密码哈希与SQL注入防护

课设文档4.2节只贴了零散代码片段,但实际运行时,90%的报错源于路由未注册、数据库连接未初始化、密码未哈希。这里给出最小可运行Flask应用骨架,包含所有角色登录验证、密码安全处理、以及防SQL注入的关键写法。

3.1 初始化应用与数据库连接

# app.py from flask import Flask, render_template, request, redirect, url_for, session, flash from flask_sqlalchemy import SQLAlchemy from werkzeug.security import generate_password_hash, check_password_hash import pymysql pymysql.install_as_MySQLdb() # 兼容PyMySQL驱动 app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key-change-in-production' # session密钥 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:your_password@127.0.0.1:3306/grade_manage_system' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) # 定义模型类(与数据库表一一对应) class Student(db.Model): __tablename__ = 'student' student_id = db.Column(db.String(10), primary_key=True) student_name = db.Column(db.String(20), nullable=False) sex = db.Column(db.String(2)) birth_year = db.Column(db.String(4)) province = db.Column(db.String(20)) enter_year = db.Column(db.String(4), nullable=False) major_id = db.Column(db.String(3), nullable=False) password = db.Column(db.String(128), nullable=False) class Teacher(db.Model): __tablename__ = 'teacher' teacher_id = db.Column(db.String(5), primary_key=True) teacher_name = db.Column(db.String(20), nullable=False) sex = db.Column(db.String(2)) birth_year = db.Column(db.String(4)) password = db.Column(db.String(128), nullable=False) class Admin(db.Model): __tablename__ = 'admin' admin_name = db.Column(db.String(15), primary_key=True, default='admin') password = db.Column(db.String(128), nullable=False)

参数说明:

  • SQLALCHEMY_DATABASE_URI中root:your_password需替换为你本地MySQL的账号密码;
  • SQLALCHEMY_TRACK_MODIFICATIONS = False关闭事件监听,减少内存占用(课设级应用无需此功能);
  • 模型类字段名与数据库列名严格一致,避免sqlalchemy.exc.InvalidRequestError。

3.2 登录路由:按角色分流与密码校验

@app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'].strip() password = request.form['password'].strip() # 管理员登录:用户名必须为'admin' if username == 'admin': admin = Admin.query.filter_by(admin_name='admin').first() if admin and check_password_hash(admin.password, password): session['role'] = 'admin' session['username'] = 'admin' return redirect(url_for('admin_dashboard')) else: flash('管理员密码错误!', 'error') return render_template('login.html') # 教师登录:用户名为teacher_id teacher = Teacher.query.filter_by(teacher_id=username).first() if teacher and check_password_hash(teacher.password, password): session['role'] = 'teacher' session['username'] = username return redirect(url_for('teacher_dashboard')) # 学生登录:用户名为student_id student = Student.query.filter_by(student_id=username).first() if student and check_password_hash(student.password, password): session['role'] = 'student' session['username'] = username return redirect(url_for('student_dashboard')) flash('用户名或密码错误!', 'error') return render_template('login.html') return render_template('login.html')

关键防护点:

  • 使用check_password_hash()校验,而非明文比对;
  • 所有查询用filter_by()而非字符串拼接(如"WHERE teacher_id = '" + username + "'"),杜绝SQL注入;
  • flash()函数向模板传递提示消息,比print()更符合Web开发规范。

3.3 密码初始化:为课设预置初始账号

# 初始化脚本:run_once.py(仅首次运行) from app import db, Student, Teacher, Admin from werkzeug.security import generate_password_hash def init_default_users(): # 插入默认管理员(密码:asdfg13579 → 哈希后存入) admin_pwd_hash = generate_password_hash('asdfg13579') admin = Admin(admin_name='admin', password=admin_pwd_hash) db.session.add(admin) # 插入示例教师(教师编号:T0001,初始密码:T0001) teacher_pwd_hash = generate_password_hash('T0001') teacher = Teacher(teacher_id='T0001', teacher_name='张老师', sex='男', birth_year='1985', password=teacher_pwd_hash) db.session.add(teacher) # 插入示例学生(学号:S2021001,初始密码:S2021001) student_pwd_hash = generate_password_hash('S2021001') student = Student(student_id='S2021001', student_name='李同学', sex='女', birth_year='2003', province='江苏', enter_year='2021', major_id='001', password=student_pwd_hash) db.session.add(student) db.session.commit() print("默认用户初始化完成!") if __name__ == '__main__': with app.app_context(): init_default_users()

执行方式:在PyCharm终端运行python run_once.py,确保数据库已创建且表结构正确。此脚本解决课设最大痛点——文档说“初始密码为学号”,但没告诉你怎么把哈希值写进数据库。

3.4 成绩录入接口:教师修改成绩的安全写法

@app.route('/teacher/update_grade', methods=['POST']) def update_grade(): if session.get('role') != 'teacher': return redirect(url_for('login')) student_id = request.form['student_id'] course_id = request.form['course_id'] new_grade = request.form['grade'] # 严格校验输入:必须是数字且在0-100 try: grade_int = int(new_grade) if not (0 <= grade_int <= 100): raise ValueError("成绩必须在0-100之间") except ValueError as e: flash(f'成绩格式错误:{e}', 'error') return redirect(url_for('teacher_course_detail', course_id=course_id)) # 使用ORM更新,非原生SQL record = db.session.query(StudentCourse).filter_by( student_id=student_id, course_id=course_id ).first() if record: record.grade = grade_int db.session.commit() flash('成绩更新成功!', 'success') else: flash('未找到该学生选课记录!', 'error') return redirect(url_for('teacher_course_detail', course_id=course_id))

为什么不用原生SQL?
db.session.query().filter_by()自动生成参数化查询,即使student_id传入'1 OR 1=1',也会被当作字符串字面量处理,不会触发SQL注入。这是课设答辩时老师最爱问的安全考点。

4. 前端界面与权限控制:基于Bootstrap 5的响应式模板与角色路由拦截

课设文档4.1节提到“借鉴网上前端模板”,但没说明如何适配Flask路由和权限。这里提供可直接替换的HTML骨架,包含角色专属导航栏、登录态保持、以及防越权访问的前端兜底逻辑。

4.1 公共基础模板(base.html)

<!-- templates/base.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}学生成绩管理系统{% endblock %}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <!-- 顶部导航栏:根据session角色动态显示 --> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="{{ url_for('index') }}">成绩管理系统</a> <button class="navbar-toggler" type="button"><!-- templates/student_dashboard.html --> {% extends "base.html" %} {% block title %}学生首页 - {{ super() }}{% endblock %} {% block content %} <div class="row"> <div class="col-md-8"> <h2>个人信息</h2> <table class="table table-bordered"> <tr><th>学号</th><td>{{ student.student_id }}</td></tr> <tr><th>姓名</th><td>{{ student.student_name }}</td></tr> <tr><th>性别</th><td>{{ student.sex }}</td></tr> <tr><th>出生年份</th><td>{{ student.birth_year }}</td></tr> <tr><th>籍贯</th><td>{{ student.province }}</td></tr> <tr><th>入学年份</th><td>{{ student.enter_year }}</td></tr> <tr><th>专业</th><td>{{ major.major_name }}</td></tr> </table> </div> <div class="col-md-4"> <h3>操作</h3> <a href="{{ url_for('student_grades') }}" class="btn btn-primary w-100 mb-2">查看成绩</a> <a href="{{ url_for('student_change_password') }}" class="btn btn-warning w-100">修改密码</a> </div> </div> {% endblock %}

关键细节:

  • 表格中{{ major.major_name }}需在视图函数中通过JOIN查询专业表获取,体现外键关联价值;
  • 按钮使用w-100(Bootstrap 5类名)占满整列宽度,适配移动端。

4.3 教师课程统计页面(teacher_statistics.html)

<!-- templates/teacher_statistics.html --> {% extends "base.html" %} {% block title %}成绩统计 - {{ super() }}{% endblock %} {% block content %} <h2>《{{ course.course_name }}》成绩分布</h2> <div class="row"> <div class="col-md-6"> <canvas id="gradeChart"></canvas> </div> <div class="col-md-6"> <h4>分数段统计</h4> <table class="table table-striped"> <thead><tr><th>分数段</th><th>人数</th></tr></thead> <tbody> <tr><td>90-100</td><td>{{ stats['A'] }}</td></tr> <tr><td>80-89</td><td>{{ stats['B'] }}</td></tr> <tr><td>70-79</td><td>{{ stats['C'] }}</td></tr> <tr><td>60-69</td><td>{{ stats['D'] }}</td></tr> <tr><td>0-59</td><td>{{ stats['F'] }}</td></tr> </tbody> </table> </div> </div> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script> const ctx = document.getElementById('gradeChart').getContext('2d'); new Chart(ctx, { type: 'doughnut', data: { labels: ['90-100', '80-89', '70-79', '60-69', '0-59'], datasets: [{ data: [{{ stats['A'] }}, {{ stats['B'] }}, {{ stats['C'] }}, {{ stats['D'] }}, {{ stats['F'] }}], backgroundColor: ['#28a745', '#17a2b8', '#ffc107', '#fd7e14', '#dc3545'] }] } }); </script> {% endblock %}

为什么用Chart.js?
课设答辩时,静态表格不如可视化图表直观。doughnut(环形图)代码仅20行,却能让老师一眼看出班级成绩分布,且CDN引入无需额外部署。

5. 避坑指南:课设答辩前必须验证的5个致命陷阱与解决方案

别让辛苦写的代码倒在最后一步。以下是我帮某高校3个班级调试课设时,高频出现的5类“答辩前2小时崩溃”问题,每一条都附带现象、根因和实操解法,照着做能省下至少8小时排查时间。

5.1 现象:Flask启动报错sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user...")

原因:SQLALCHEMY_DATABASE_URI中的MySQL账号密码错误,或该账号无grade_manage_system数据库权限。
解决:

  1. 在MySQL命令行执行SELECT User,Host FROM mysql.user;确认账号存在;
  2. 执行CREATE USER 'root'@'localhost' IDENTIFIED BY 'your_password';(若账号不存在);
  3. 执行GRANT ALL PRIVILEGES ON grade_manage_system.* TO 'root'@'localhost'; FLUSH PRIVILEGES;授予库权限;
  4. 检查app.py中URI是否为mysql://root:your_password@127.0.0.1:3306/grade_manage_system(注意端口3306和数据库名拼写)。

5.2 现象:登录后跳转admin_dashboard页面,但显示jinja2.exceptions.UndefinedError: 'admin' is undefined

原因:视图函数未将admin对象传入模板,或模板中变量名与render_template()参数名不一致。
解决:
检查admin_dashboard()函数:

@app.route('/admin') def admin_dashboard(): # 错误写法:return render_template('admin.html') → 模板收不到admin数据 # 正确写法: admins = Admin.query.all() # 查询所有管理员(课设通常只有1个) return render_template('admin.html', admins=admins) # 参数名admins必须与模板中{{ admins }}一致

5.3 现象:学生登录后,student_grades.html页面显示“暂无成绩”,但数据库student_course表里明明有数据

原因:student_course表中student_id或course_id字段类型与student/course表主键类型不匹配(如student_id在student表是CHAR(10),但在student_course表误建为VARCHAR(10)),导致JOIN失败。
解决:

  1. 执行DESCRIBE student_course;查看字段类型;
  2. 执行DESCRIBE student;和DESCRIBE course;对比主键类型;
  3. 若不一致,用ALTER TABLE student_course MODIFY student_id CHAR(10);修正(注意备份数据)。

5.4 现象:修改密码功能提交后,新密码仍是明文存入数据库,且下次登录失败

原因:前端表单提交的密码未经过generate_password_hash()处理,或视图函数中漏掉哈希步骤。
解决:
检查密码修改路由:

@app.route('/student/change_password', methods=['POST']) def change_student_password(): old_pwd = request.form['old_password'] new_pwd = request.form['new_password'] confirm_pwd = request.form['confirm_password'] if new_pwd != confirm_pwd: flash('两次输入的新密码不一致!', 'error') return redirect(url_for('student_change_password')) student = Student.query.filter_by(student_id=session['username']).first() if not check_password_hash(student.password, old_pwd): # 先校验旧密码 flash('原密码错误!', 'error') return redirect(url_for('student_change_password')) # 关键:必须哈希新密码! student.password = generate_password_hash(new_pwd) # ← 这行不能少 db.session.commit() flash('密码修改成功!', 'success') return redirect(url_for('student_dashboard'))

5.5 现象:点击“添加学生”按钮,页面空白或报500 Internal Server Error,日志显示sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1048, "Column 'major_id' cannot be null")

原因:前端表单未提交major_id字段,或后端未从表单中读取该字段。
解决:

  1. 检查admin_add_student.html中是否有<select name="major_id">下拉框,且选项值为major_id(如<option value="001">计算机</option>);
  2. 检查视图函数是否读取:
@app.route('/admin/add_student', methods=['POST']) def add_student(): student_id = request.form['student_id'] student_name = request.form['student_name'] # ...其他字段 major_id = request.form['major_id'] # ← 必须读取,不能漏 password_hash = generate_password_hash(student_id) # 初始密码为学号 new_student = Student( student_id=student_id, student_name=student_name, # ...其他字段 major_id=major_id, # ← 必须赋值 password=password_hash ) db.session.add(new_student) db.session.commit()

6. 本地一键启动与答辩演示技巧:从双击到流畅演示的3个关键动作

课设答辩不是代码审查,而是限时3分钟的现场演示。我总结出一套“开机→启动→演示→收尾”全流程,确保你在老师面前不卡顿、不报错、不手抖。

6.1 启动前的终极检查清单(每次答辩前必做)

检查项操作方式为什么重要
MySQL服务状态Windows任务管理器→服务→确认MySQL80状态为“正在运行”服务未启动是课设第一大死因,比代码错误更常见
数据库是否存在MySQL命令行执行SHOW DATABASES LIKE 'grade_manage_system';防止因建库脚本执行失败导致Flask连空库
默认管理员已初始化执行SELECT * FROM admin;确认返回1条记录,password字段为60+字符哈希串避免登录页输admin/asdfg13579后提示“密码错误”
初始学生/教师数据存在SELECT * FROM student LIMIT 1;和SELECT * FROM teacher LIMIT 1;确保演示时有真实数据可查,不出现“暂无数据”尴尬

6.2 PyCharm一键启动配置(告别命令行cd)

在PyCharm中右键app.py→Run 'app'前,必须配置:

  1. Working directory: 设置为项目根目录(含templates/和static/的文件夹);
  2. Environment variables: 添加PYTHONPATH=$ProjectFileDir$(Windows用%PROJECT_DIR%);
  3. Run with Python Console: 取消勾选(避免启动后卡在console界面)。

玄学提示:首次运行时,PyCharm可能提示“Flask is not installed”,点击Install package flask自动安装,比手动pip install更稳定。

6.3 答辩演示话术与节奏控制(3分钟黄金流程)

  • 第0-30秒(启动):
    “老师好,我现在启动系统。(双击PyCharm Run按钮)您看,控制台输出* Running on http://127.0.0.1:5000,说明服务已就绪。”
  • 第30-90秒(登录与核心功能):
    “我先以管理员身份登录,用户名admin,密码asdfg13579。(输入后回车)进入管理后台,我添加一名学生——学号S2021002,姓名王同学,专业编号001。(点击提交)再添加一门课程——编号C0001,名称数据库原理。(提交)现在切换教师身份,用T0001登录,给王同学录入成绩95分。(操作)”
  • 第90-180秒(学生视角验证):
    “最后以学生身份登录,学号S2021002,密码S2021002。(登录)您看,个人信息、所选课程、成绩95分全部显示正常。点击‘成绩统计’,环形图清晰展示班级整体表现。”

关键技巧:所有账号密码提前写在便签纸上,避免现场回忆;演示用Chrome无痕窗口,防止缓存干扰;每步操作后停顿1秒,让老师看清界面变化。

从那以后我每次准备课设答辩,都强制走一遍这个检查清单:先确认MySQL服务,再查数据库和默认用户,最后用三个角色各走一遍登录→操作→退出。哪怕凌晨两点调试到崩溃,只要这三步通了,答辩就稳了一半。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表