简介:这是一套面向计算机相关专业在校学生与初学者的医院管理系统实战项目,采用Python结合MySQL实现,可作为数据库课程设计、毕业设计或课程大作业的参考方案,也适合想通过完整项目进阶练手的小白。压缩包共22个文件,约43KB,以10个Python源码文件为核心,配套7个pyc编译文件、4个SQL脚本及1个xlsx数据表,涵盖数据库连接、数据初始化、数据查询、数据字典与业务操作等模块,SQL脚本则负责建表、触发器、数据插入与初始化。项目代码均经过测试运行成功后才上传,功能可用,读者可直接部署体验,也能在此基础上修改扩展,实现更多业务功能。目前已有557人学习下载,适合需要快速获取完整课设方案、理解Python与MySQL协作流程、积累项目排错经验的读者参考借鉴。
1. 从一份课设压缩包说起:Python + MySQL 医院管理系统到底能跑出什么
如果你正在为数据库课设或者毕业设计找一份能跑通、能改、能讲清楚原理的参考实现,这个基于 Python 和 MySQL 的医院管理系统源码包值得先看一眼。它不是一个空壳 Demo,而是把挂号、医生排班、患者信息、药品库存这些医院业务里最典型的数据流,用 Python 脚本加 MySQL 表结构完整串了起来。压缩包里既有hospital.py这样的主入口,也有dataInitiator.py、dataSearcher.py、dataOperator.py这些职责拆得很细的模块,还配了四份 SQL 文件分别处理建表、初始化、触发器和补充数据。换句话说,你拿到的是一套能直接导入数据库、跑起交互菜单、看到数据增删改查效果的完整课设素材。适合谁?计算机相关专业做课程大作业的学生、需要快速搭一个业务系统原型练手的开发者,以及想看看 Python 操作 MySQL 在真实业务表结构下怎么写才不翻车的人。下面我按实际拆包和复现的顺序,把这份资源从环境准备到进阶改造讲透。
2. 拆开压缩包先看什么:模块划分与数据库脚本的对应关系
2.1 八个 Python 文件各自管什么
拿到压缩包别急着pip install,先把文件列表过一遍。根目录下能看到hospital.py、dataInitiator.py、dbConnector.py、dataSearcher.py、dataDictionary.py、dataOperator.py、dataReader.py,以及mysql01.py、mysql02.py、mysql03.py这几个编号脚本。从命名就能猜出大致分工:dbConnector.py负责数据库连接和游标管理,dataInitiator.py负责把初始数据灌进表里,dataSearcher.py封装查询逻辑,dataOperator.py处理增删改,dataDictionary.py大概率是字段映射或菜单字典,dataReader.py负责从 Excel 或控制台读取输入。hospital.py是主程序入口,把上面这些模块串起来形成交互菜单。mysql01.py到mysql03.py更像是分步骤的数据库操作示例或迁移脚本,具体用途要打开看 import 和 SQL 语句才能确认。
这种拆法在课设里算比较规范的,好处是每个文件职责单一,改一个功能不用翻遍整个项目。坏处是模块间依赖靠相对导入,如果你直接双击hospital.py运行,可能会遇到ModuleNotFoundError。常见做法是在项目根目录下用python hospital.py启动,而不是进到子目录里执行。
2.2 四份 SQL 文件的执行顺序不能乱
mysql files目录下的四份 SQL 文件是整套系统的地基,顺序错了表结构对不上,后面 Python 代码全报错。按文件名和常见课设惯例,执行顺序应该是:
| 顺序 | 文件名 | 作用 | 关键注意点 |
|---|---|---|---|
| 1 | 2022.5.1 hospital init.sql | 建库建表、定义主外键 | 先确认库名和字符集 |
| 2 | 2022.5.1 hospital data insert.sql | 插入初始业务数据 | 依赖表结构已存在 |
| 3 | 2022.5.1 hospital triggers.sql | 创建触发器 | 部分触发器依赖已有数据 |
| 4 | 2022.5.1 hospital others.sql | 视图、存储过程或补充约束 | 最后执行,避免依赖缺失 |
我一般会先在 MySQL 命令行里source第一份文件,确认SHOW TABLES;能看到患者表、医生表、挂号表、药品表这些核心表,再往下走。如果直接四份一起灌,触发器可能因为引用的表还没数据而创建失败,这种错误在课设里很常见,但排查起来费时间。
2.3 连接配置藏在哪个文件里
dbConnector.py通常是唯一需要改配置的地方。打开后你会看到类似host、user、password、database、charset这几个参数。默认值可能是localhost、root、空密码或者123456,数据库名大概率是hospital或hospital_db。这里有个血泪经验:如果你的 MySQL 是 8.0 版本,charset建议显式写成utf8mb4,否则中文患者姓名和药品名称插进去可能变问号。另外port默认 3306,如果你本机装过多个 MySQL 实例,确认一下实际端口。
改完配置后,先别跑主程序,单独执行python dbConnector.py看能不能打印出连接成功的信息。很多课设代码会在dbConnector.py里加一个if __name__ == '__main__':的自测块,有的话正好用来验证。没有的话就手动写两行测试代码,确认连接对象能创建、游标能执行SELECT 1。这一步过了,后面才谈得上业务逻辑。
3. 把环境跑起来:从建库到主菜单出现的完整操作链
3.1 建库导数据的命令行操作
假设你已经装好了 MySQL 5.7 或 8.0,并且mysql命令在 PATH 里。先登录:
mysql -u root -p输入密码后进入交互界面,创建数据库并指定字符集:
CREATE DATABASE hospital DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE hospital;然后依次导入四份 SQL 文件。注意路径要写你解压后的实际路径,Windows 下反斜杠要转义或者用正斜杠:
source /path/to/mysql files/2022.5.1 hospital init.sql; source /path/to/mysql files/2022.5.1 hospital data insert.sql; source /path/to/mysql files/2022.5.1 hospital triggers.sql; source /path/to/mysql files/2022.5.1 hospital others.sql;每执行完一份,用SHOW TABLES;和SELECT COUNT(*) FROM 某张表;确认结果。如果init.sql里已经包含了CREATE DATABASE和USE语句,那前面手动建库那步可以跳过,但字符集还是要确认。导入过程中如果报ERROR 1064语法错误,大概率是 SQL 文件里用了 MySQL 8.0 不兼容的旧语法,比如TYPE = MyISAM这种,改成ENGINE = InnoDB就行。
3.2 Python 依赖与连接测试
这套代码大概率只依赖pymysql或者mysql-connector-python,外加openpyxl或pandas来处理data.xlsx。先看requirements.txt有没有,没有的话就按 import 语句反推。常见安装命令:
pip install pymysql openpyxl如果你用的是 Anaconda 环境,注意 pip 和 conda 混用可能导致包路径冲突,建议统一用 pip 或者统一用 conda。装完后写一个最小连接测试:
import pymysql conn = pymysql.connect( host='localhost', user='root', password='你的密码', database='hospital', charset='utf8mb4' ) cursor = conn.cursor() cursor.execute('SELECT VERSION();') print(cursor.fetchone()) cursor.close() conn.close()这段代码能打印出 MySQL 版本号,说明驱动、网络、账号权限、数据库名都没问题。如果报Access denied,检查密码和用户权限;如果报Unknown database,说明库名写错了或者没建库;如果报Can't connect,确认 MySQL 服务是否启动、端口是否被占用。
3.3 启动主程序与菜单交互
连接测试通过后,在项目根目录执行:
python hospital.py正常情况下会看到一个文本菜单,比如「1. 患者管理 2. 医生管理 3. 挂号管理 4. 药品管理 0. 退出」之类的选项。输入数字回车,进入对应子菜单,再按提示输入患者编号、姓名、科室等信息。这里有个玄学问题:如果你在 PyCharm 里直接点运行按钮,工作目录可能是项目根目录也可能是脚本所在目录,导致data.xlsx读不到。稳妥做法是在终端里cd到项目根目录再执行,或者在代码里用os.path.dirname(os.path.abspath(__file__))拼绝对路径。
菜单能出现、能选、能查到数据,说明整套链路通了。接下来才是改代码和加功能的阶段。
4. 改代码前先看懂数据流:查询、插入与触发器怎么配合
4.1 dataSearcher 与 dataOperator 的调用关系
dataSearcher.py和dataOperator.py是业务逻辑最集中的两个文件。dataSearcher里通常封装了按条件查患者、查医生排班、查药品库存的方法,每个方法接收参数后拼 SQL 的WHERE子句,返回字典或元组列表。dataOperator则处理INSERT、UPDATE、DELETE,并且往往会在操作成功后提交事务。看这段典型代码:
# dataSearcher.py 片段 def search_patient_by_name(self, name): sql = "SELECT patient_id, patient_name, gender, phone FROM patient WHERE patient_name LIKE %s" self.cursor.execute(sql, ('%' + name + '%',)) return self.cursor.fetchall()注意LIKE后面的参数用了%s占位符,而不是字符串拼接。这是防 SQL 注入的基本操作,课设里如果看到"WHERE name = '" + name + "'"这种写法,建议直接改掉,答辩时被问到也好看。dataOperator里插入患者信息的代码类似:
# dataOperator.py 片段 def add_patient(self, name, gender, phone): sql = "INSERT INTO patient (patient_name, gender, phone) VALUES (%s, %s, %s)" self.cursor.execute(sql, (name, gender, phone)) self.conn.commit()参数说明:name、gender、phone分别对应患者表的字段,顺序不能错。如果表里有自增主键,不用手动传。commit()必须调用,否则数据只在当前会话可见,换个连接就查不到。
4.2 触发器在挂号流程里起什么作用
2022.5.1 hospital triggers.sql里定义的触发器,常见的有两类:一类是挂号成功后自动扣减医生当日号源,另一类是药品出库后自动更新库存数量。这类逻辑放在数据库层的好处是,不管你是从 Python 菜单操作还是直接手动执行 SQL,约束都会生效。但坑也在这里:如果触发器逻辑写错了,插入挂号记录时可能报ERROR 1442或者静默失败,而 Python 端只看到commit没报错,以为成功了。
排查方法是在 MySQL 里执行SHOW TRIGGERS;看触发器列表,再用SHOW CREATE TRIGGER 触发器名;看具体定义。如果触发器里引用了不存在的字段或者表名拼错,创建时可能不报错,但执行时一定翻车。我一般会在导入触发器后,手动插一条测试数据,看关联表的数量有没有按预期变化。
4.3 data.xlsx 和 dataReader 的配合
data.xlsx大概率是批量导入的模板文件,dataReader.py负责读取它并转成 Python 列表或字典。常见实现是用openpyxl逐行读:
# dataReader.py 片段 from openpyxl import load_workbook def read_patients_from_excel(self, filepath): wb = load_workbook(filepath) ws = wb.active patients = [] for row in ws.iter_rows(min_row=2, values_only=True): patients.append({ 'name': row[0], 'gender': row[1], 'phone': row[2] }) return patients参数说明:min_row=2表示跳过表头,values_only=True直接拿单元格的值而不是对象。如果 Excel 里有日期或数字格式,读出来可能是datetime对象或float,插入 MySQL 前要转成字符串或对应类型。这一步不做转换的话,phone字段可能变成13800138000.0这种带小数点的形式,查的时候对不上。
5. 避坑与排查:课设代码跑不起来时先查这五条
5.1 报 ModuleNotFoundError: No module named 'pymysql'
现象:执行python hospital.py立刻报找不到模块。原因:当前 Python 环境没装pymysql,或者你装了但 IDE 用的解释器不是同一个。解决:在终端里pip install pymysql,然后在 IDE 设置里确认项目解释器路径和终端which python输出一致。如果用了虚拟环境,先激活再装。
5.2 中文数据插入后显示为问号
现象:患者姓名、药品名称在数据库里查出来是???。原因:连接字符集或表字符集不是utf8mb4。解决:检查dbConnector.py里charset参数,改成utf8mb4;再检查建表语句里有没有DEFAULT CHARSET=utf8,有的话改成utf8mb4。已经建好的表可以用ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4;补救。
5.3 触发器导致插入失败但 Python 不报错
现象:挂号记录没插进去,但程序没抛异常。原因:触发器里逻辑有误,比如引用了不存在的字段,MySQL 可能返回警告而非错误,Python 的commit照样执行。解决:在dataOperator的插入方法里加self.cursor.execute("SHOW WARNINGS;")打印警告,或者直接在 MySQL 命令行手动执行同样的 INSERT 看报什么错。
5.4 主菜单一闪而过或直接退出
现象:双击hospital.py窗口闪一下就没了。原因:程序执行完主循环后正常退出,或者启动时就抛异常但窗口关闭太快看不到。解决:在终端里运行而不是双击,这样报错信息会留在屏幕上。如果是正常退出,检查主循环的while条件是不是写成了False或者没有input阻塞。
5.5 外键约束导致删除失败
现象:删除某个医生时提示Cannot delete or update a parent row。原因:该医生在挂号表或排班表里还有关联记录,外键约束阻止删除。解决:先删子表关联记录再删主表,或者在建表时把外键的ON DELETE行为改成CASCADE。课设里如果不想改表结构,就在dataOperator的删除方法里先查关联再决定是否允许删。
6. 进阶改造与验证:把课设变成能讲出亮点的项目
6.1 加一个按科室统计挂号量的查询
原始代码里可能只有按患者或医生查,缺聚合统计。你可以在dataSearcher.py里加一个方法:
def count_registrations_by_department(self): sql = """ SELECT d.department_name, COUNT(*) AS total FROM registration r JOIN doctor doc ON r.doctor_id = doc.doctor_id JOIN department d ON doc.department_id = d.department_id GROUP BY d.department_name ORDER BY total DESC """ self.cursor.execute(sql) return self.cursor.fetchall()然后在hospital.py的菜单里加一个选项调用它,打印结果。这个改动不大,但答辩时能展示你会用JOIN和GROUP BY,比单纯增删改查有说服力。参数说明:COUNT(*)统计每个科室的挂号总数,ORDER BY total DESC让最多的排前面。
6.2 用事务保证挂号扣号的一致性
如果触发器已经处理了扣号,Python 端可以不再重复。但如果你想在应用层控制,可以把插入挂号和更新号源放在同一个事务里:
def register_with_transaction(self, patient_id, doctor_id): try: self.cursor.execute( "INSERT INTO registration (patient_id, doctor_id, reg_time) VALUES (%s, %s, NOW())", (patient_id, doctor_id) ) self.cursor.execute( "UPDATE doctor_schedule SET remain = remain - 1 WHERE doctor_id = %s AND remain > 0", (doctor_id,) ) if self.cursor.rowcount == 0: raise Exception("号源不足") self.conn.commit() except Exception as e: self.conn.rollback() print("挂号失败:", e)这段代码的关键是rollback(),一旦扣号失败,插入的挂号记录也会回滚,不会出现挂了号但没扣号的脏数据。rowcount == 0判断更新是否命中了行,没命中说明号源已满。
6.3 验证数据一致性的两个 SQL
改完代码后,别只看菜单能不能点,跑两个校验 SQL:
-- 检查挂号表里的医生是否都存在于医生表 SELECT COUNT(*) FROM registration r LEFT JOIN doctor d ON r.doctor_id = d.doctor_id WHERE d.doctor_id IS NULL; -- 检查药品库存是否出现负数 SELECT * FROM medicine WHERE stock < 0;第一条返回 0 说明没有孤儿记录,第二条返回空说明触发器或事务逻辑没把库存扣穿。这两个查询我每次改完数据库相关代码都会跑一遍,比点菜单靠谱。
6.4 从课设到毕设的扩展方向
如果你打算把这个项目往毕设方向扩,优先考虑加登录鉴权和操作日志。登录可以建一张user表,存用户名和哈希后的密码,Python 端用hashlib做摘要。操作日志可以在dataOperator的每个写方法里插一条记录到log表,记下操作人、时间、动作。这两个功能不复杂,但能让系统从「课设 Demo」变成「有基本安全意识的业务原型」。另外,把data.xlsx的批量导入做成带校验的流程,比如手机号格式不对就跳过并记录行号,也是答辩时能展开讲的点。
从那以后我每次拿到这种课设压缩包,都先按「建库顺序 → 连接测试 → 主菜单 → 触发器验证 → 一致性 SQL」走一遍,确认地基没问题再动代码。希望帮到你。
本文还有配套的精品资源,点击获取