首页 / 资讯中心 / 文章详情

Python选课系统源码解析:PyQt5与SQLite环境搭建及避坑指南

Python选课系统源码解析:PyQt5与SQLite环境搭建及避坑指南 ★ FEATURED ARTICLE
简介这份资源是一套基于Python开发的选课信息管理系统源码面向教育机构信息化建设者、计算机专业学生及Python初学者用于快速搭建学生选课与课程管理平台。压缩包共147个文件约81.61MB包含81个dll动态链接库、22个qm翻译文件、14个pyd与9个pyc编译模块、9个py源码以及2个db数据库、2个jpg界面图片和qrc、ui、spec等资源与工程文件结构完整兼顾运行依赖与二次开发。系统按学生选课主函数、显示、主界面、查询和教师端等模块划分数据库存储课程、选课记录与教师信息教师端可管理课程并查看选课情况查询模块便于快速检索课程。目前已有306人学习下载适合作为课程设计或毕业设计参考读者可借此理解模块化分层设计、数据库持久化与界面资源组织方式并在此基础上扩展功能或优化交互流程。1. 拆开一个 146 文件的 Python 选课系统它到底能跑起来吗网上下载的 Python 课程设计源码十个里有八个解压完就报错剩下两个能启动但数据库是空的。这次拿到的这份「基于 Python 的选课信息管理系统」有点不一样——146 个文件里81 个 DLL、22 个 QM、14 个 PYD、9 个 PYC、9 个 PY外加 2 个 DB 和 1 个 QRC。看到这个文件构成第一反应不是「功能多全」而是「这是一个已经用 PyInstaller 或类似工具打包过的桌面程序不是裸源码」。对正在找 Python 课程设计案例源码的人来说这个包的价值在于它给了一个完整的、带 Qt 界面的选课系统落地样本学生选课主函数、显示模块、主界面、查询、教师端五个模块都在数据库文件也是现成的。适合两类人——需要交课程设计但不想从零搭界面的学生以及想研究 PyQt 桌面应用怎么和 SQLite 配合的开发者。但它不是 pip install 就能跑的那种项目DLL 和 PYD 的存在意味着你得先搞清楚运行环境。2. 文件构成决定运行方式先分清 PY 和 PYD 的角色2.1 9 个 PY 是入口14 个 PYD 是编译后的模块拿到包先别急着双击 exe。把目录结构理一遍你会发现真正能读的 Python 源码只有 9 个 .py 文件其余的逻辑被编译进了 .pyd 和 .pyc。这是典型的「源码 编译产物混合」打包方式常见于课程设计提交时用 PyInstaller 或 Cython 处理过核心模块。先确认哪些文件是你能改的# 列出所有 Python 相关文件按类型分组 find . -name *.py -o -name *.pyd -o -name *.pyc | sort # 查看 PY 文件的内容规模判断哪个是主入口 wc -l *.py执行完你会看到类似main.py、student_select.py、query.py、teacher.py这样的命名。9 个 PY 文件里通常有一个是启动入口其余是各功能模块。PYD 文件不用管它们是编译好的二进制模块Python 版本不匹配时直接报ImportError。参数说明find命令里的-o是逻辑或把三类文件一次性列出来wc -l统计行数行数最多的那个 PY 大概率是主界面或主逻辑。如果某个 PY 只有几十行它可能只是个启动壳真正的逻辑在 PYD 里。2.2 DLL 和 QM 文件告诉你这是 PyQt5 SQLite 的组合81 个 DLL 里Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll、Qt5Qml.dll这几个名字直接暴露了 GUI 框架——PyQt5。opengl32sw.dll是 Qt 的软件渲染回退d3dcompiler_47.dll是 Direct3D 编译库说明界面用了 Qt 的图形渲染管线。python37.dll则锁定了 Python 版本3.7。22 个 QM 文件是 Qt 的翻译文件通常放在translations目录下。如果你不需要多语言这些文件不影响运行。2 个 DB 文件是 SQLite 数据库用sqlite3命令行就能打开查看表结构# 查看数据库里有哪些表 sqlite3 学生选课系统.db .tables # 查看某张表的结构比如课程表 sqlite3 学生选课系统.db .schema courses # 快速看一眼前 5 条数据 sqlite3 学生选课系统.db SELECT * FROM courses LIMIT 5;逻辑说明.tables列出所有表名通常会有students、courses、enrollments、teachers这几张。.schema看字段定义重点确认主键和外键关系。如果 DB 文件是空的或者表不存在说明这个包只给了结构没给数据你得自己造测试数据。注意Python 3.7 的 PYD 文件在 Python 3.8 环境下无法导入会报ImportError: DLL load failed。这是第一个大坑后面避坑章节会展开。3. 把环境搭到能启动Python 3.7 PyQt5 的版本对齐3.1 为什么必须用 Python 3.7 而不是最新版python37.dll这个文件名不是随便起的。PYD 文件在编译时绑定了具体的 Python ABI 版本3.7 编译的 PYD 拿到 3.11 环境下Python 解释器会直接拒绝加载。你可能会想「那我重新编译 PYD 不就行了」——可以但前提是你有对应的 .pyx 或 .py 源文件而这个包里核心逻辑已经编译成 PYD 了重新编译不现实。所以最省事的路径是装一个 Python 3.7。如果你机器上已经有其他版本用 conda 建独立环境最干净# 用 conda 创建 Python 3.7 环境 conda create -n course_sys python3.7 -y conda activate course_sys # 确认版本 python --version # 应输出 Python 3.7.x如果没有 conda去 Python 官网下载 3.7.9 的安装包安装时勾选「Add to PATH」但注意不要覆盖系统里已有的 Python。Windows 上可以用py -3.7来指定版本。参数说明-n course_sys是环境名随便取python3.7不写小版本号conda 会自动选 3.7 系列最新的。装完后which python确认路径指向 conda 环境而不是系统 Python。3.2 装 PyQt5 和依赖版本号不能随便选Python 3.7 对应的 PyQt5 版本有讲究。PyQt5 5.15.x 是支持 3.7 的最后一个大版本系列再新的 6.x 不支持 3.7。直接 pip 装最新版会翻车# 在 Python 3.7 环境下安装匹配的 PyQt5 pip install PyQt55.15.4 PyQt5-tools5.15.4.3.2 # 验证安装 python -c from PyQt5.QtWidgets import QApplication; print(PyQt5 OK)逻辑说明PyQt55.15.4锁定版本避免 pip 解析到不兼容的新版。PyQt5-tools包含 Qt Designer 等工具如果包里已经有 .ui 转 .py 的文件这个可以不装。验证那行如果输出了PyQt5 OK说明 GUI 框架就绪。如果 pip 装的时候报编译错误大概率是缺少 Visual C 运行库。Windows 上装一个 VC 2015-2019 运行库即可这不是 Python 包的问题。3.3 启动顺序先跑主入口再看报错环境搭好后找到主入口 PY 文件。通常叫main.py或学生选课主函数.py。先别急着改代码直接跑# 进入源码目录 cd 选课系统源码目录 # 运行主入口 python main.py如果窗口弹出来了恭喜你环境对齐了。如果报ModuleNotFoundError看缺哪个模块用 pip 补装。如果报ImportError: DLL load failed回到 3.1 检查 Python 版本。如果报数据库相关错误检查 DB 文件路径是不是硬编码的绝对路径——这是课程设计源码的常见毛病。提示有些包的主入口是 exe 而不是 py。如果目录里有 exe先双击试试能跑起来说明打包时环境已经带上了你只需要研究源码逻辑即可。4. 五个功能模块怎么串起来从选课主函数到教师端4.1 学生选课主函数流程入口和状态管理学生选课主函数模块是整个系统的启动点。它负责初始化数据库连接、加载用户身份、渲染主界面然后把控制权交给各个子模块。在 9 个 PY 文件里这个文件通常行数最多因为它要处理登录态、课程列表加载、选课按钮事件绑定这些杂事。典型的代码结构长这样# 学生选课主函数.py 的核心逻辑示意 import sqlite3 from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox class CourseSelectionSystem(QMainWindow): def __init__(self): super().__init__() self.db_path 学生选课系统.db # 数据库路径可能需要改成绝对路径 self.conn sqlite3.connect(self.db_path) self.cursor self.conn.cursor() self.current_student_id None # 登录后赋值 self.init_ui() def init_ui(self): # 加载主界面、绑定按钮事件 pass def load_courses(self): # 查询可选课程填充到表格控件 self.cursor.execute(SELECT course_id, course_name, teacher, capacity FROM courses) return self.cursor.fetchall() def enroll_course(self, course_id): # 选课核心逻辑检查容量、写入选课记录 self.cursor.execute(SELECT capacity, enrolled FROM courses WHERE course_id?, (course_id,)) row self.cursor.fetchone() if row and row[1] row[0]: self.cursor.execute(INSERT INTO enrollments (student_id, course_id) VALUES (?, ?), (self.current_student_id, course_id)) self.conn.commit() return True return False逻辑说明__init__里建立数据库连接load_courses查课程列表enroll_course是选课的核心——先查容量没满才写入选课记录。参数course_id来自界面上的课程选择current_student_id在登录成功后赋值。这段代码里最值得关注的是enroll_course的容量检查逻辑。很多课程设计源码在这里只做了「插入记录」而不检查容量导致选课人数可以无限超出。如果你要改就在这个函数里加并发控制——SQLite 用事务包一下。4.2 查询模块和教师端两个容易被忽略的边界查询模块负责按课程名、教师名、学分等条件检索课程。它的实现通常是一个带输入框和搜索按钮的界面背后拼 SQL 的WHERE子句。这里有个常见问题字符串拼接 SQL 会导致注入虽然课程设计不太在意安全但改成参数化查询也就多写一行的事。教师端模块的功能是查看已选学生名单、修改课程容量、录入成绩。它和学生端的区别在于权限——教师登录后看到的界面不同能操作的数据范围也不同。在数据库层面通常用role字段区分身份或者在teachers表里单独存教师账号。# 教师端查看某门课的选课名单 def get_enrolled_students(self, course_id): self.cursor.execute( SELECT s.student_id, s.name, e.enroll_time FROM enrollments e JOIN students s ON e.student_id s.student_id WHERE e.course_id ? , (course_id,)) return self.cursor.fetchall()逻辑说明这条 SQL 用 JOIN 把选课记录和学生信息连起来enroll_time是选课时间戳。参数course_id由教师在界面上选择。如果查询结果为空检查enrollments表里有没有对应记录以及student_id是否匹配。注意如果教师端和学生端共用同一个数据库连接切换用户时记得重新查询权限相关数据不要缓存上一个用户的身份信息。5. 避坑排查DLL 加载失败、数据库路径和编码问题5.1 现象启动时报ImportError: DLL load failed while importing QtCore原因Python 版本和 PYD/DLL 不匹配。python37.dll说明整个包是在 Python 3.7 下打包的你用 3.8 或更高版本跑Qt 的 PYD 模块找不到对应的 Python ABI。解决装 Python 3.7 并用它运行。如果已经装了 3.7 还报这个错检查 PATH 里是不是有多个 Python 版本用where pythonWindows或which pythonLinux/Mac确认当前用的是哪个。conda 环境激活后一般不会有这个问题。5.2 现象窗口能打开但课程列表是空的原因数据库路径写的是绝对路径比如D:\课程设计\学生选课系统.db你的机器上没这个目录。或者 DB 文件里courses表本身就没有数据。解决先确认 DB 文件在不在当前目录然后用 sqlite3 查一下SELECT COUNT(*) FROM courses;。如果是路径问题把代码里的db_path改成相对路径os.path.join(os.path.dirname(__file__), 学生选课系统.db)。如果是数据问题自己 INSERT 几条测试数据。5.3 现象中文显示成乱码或方框原因Qt 默认字体不支持中文或者源码文件编码不是 UTF-8。Python 3 默认源码编码是 UTF-8但如果文件是从 Windows 下用 GBK 保存的读出来就是乱码。解决在入口文件开头加# -*- coding: utf-8 -*-并确认文件本身用 UTF-8 保存。Qt 界面乱码的话在QApplication创建后设置字体app.setFont(QFont(Microsoft YaHei, 10))。5.4 现象选课按钮点了没反应也不报错原因按钮的clicked信号没有绑定到槽函数或者槽函数里抛了异常但被 Qt 吞掉了。解决在槽函数入口加print或logging确认函数有没有被调用。如果没被调用检查button.clicked.connect(self.enroll_course)这行是不是漏了。如果被调用了但没反应在数据库操作外面包try/except把异常打出来。5.5 现象打包成 exe 后在其他电脑上跑不起来原因PyInstaller 打包时没有把 Qt 的 DLL 和 QM 文件完整带上或者目标机器缺少 VC 运行库。解决用pyinstaller --add-data *.dll;. --add-data *.qm;translations main.py重新打包确保 DLL 和翻译文件都在。目标机器上装 VC 2015-2019 运行库。如果还是不行用 Dependency Walker 看缺哪个 DLL。6. 二次开发切入点改数据库结构和加新功能6.1 先摸清表关系再动手改拿到这个包最值钱的不是界面是那 2 个 DB 文件里的表结构。用 sqlite3 把.schema全部导出来画个简单的 ER 图纸上画就行搞清楚students、courses、enrollments、teachers四张表的主外键关系。这是你加功能的基础。# 导出所有表的建表语句 sqlite3 学生选课系统.db .schema schema.sql # 查看每张表的记录数判断数据完整度 sqlite3 学生选课系统.db SELECT students, COUNT(*) FROM students UNION ALL SELECT courses, COUNT(*) FROM courses UNION ALL SELECT enrollments, COUNT(*) FROM enrollments;逻辑说明.schema导出建表语句方便你对照修改。第二条 SQL 用 UNION ALL 把三张表的记录数拼在一起输出一眼就能看出哪张表是空的。如果enrollments是 0 条说明选课记录没初始化你得自己造。6.2 加一个「退课」功能从数据库到界面的完整链路退课功能是选课系统的标配但这个包里不一定有。加退课需要动三个地方数据库加删除操作、主函数加退课方法、界面加退课按钮。# 在 CourseSelectionSystem 类里加退课方法 def drop_course(self, course_id): # 先确认该学生确实选了这门课 self.cursor.execute(SELECT * FROM enrollments WHERE student_id? AND course_id?, (self.current_student_id, course_id)) if not self.cursor.fetchone(): QMessageBox.warning(self, 提示, 你未选择该课程) return False # 删除选课记录 self.cursor.execute(DELETE FROM enrollments WHERE student_id? AND course_id?, (self.current_student_id, course_id)) # 更新课程已选人数 self.cursor.execute(UPDATE courses SET enrolled enrolled - 1 WHERE course_id?, (course_id,)) self.conn.commit() return True逻辑说明先查enrollments表确认记录存在避免误删。删除后同步更新courses表的enrolled字段保持数据一致。参数course_id从界面传入current_student_id是当前登录学生。界面那边加一个按钮clicked信号绑到这个方法上就行。6.3 验证改动用 SQL 直接查结果别只信界面改完代码后不要只看界面刷新了没有。直接查数据库确认数据变了-- 退课前后的对比查询 SELECT course_id, enrolled FROM courses WHERE course_id CS101; SELECT * FROM enrollments WHERE student_id 2023001 AND course_id CS101;如果enrolled减了 1 且enrollments里对应记录没了说明退课逻辑正确。如果界面显示退了但数据库没变检查self.conn.commit()有没有执行——SQLite 不 commit 的话改动只在内存里。从那以后我每次改完数据库相关的代码都强制走一遍「界面操作 → SQL 查库 → 对比预期」的流程不看到 SQL 结果不算改完。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站