简介这套基于Python和MySQL的医院管理系统面向计算机相关专业在校生、毕业设计及数据库课程设计场景可用于快速搭建一个具备数据初始化、信息查询、业务操作等核心功能的管理项目也可作为初学Python与MySQL联动开发的练手案例。压缩包共22个文件约43KB主要包含10个Python源码文件实现数据库连接、数据初始化、查询与操作逻辑、4个SQL脚本建表、初始数据及触发器、7个编译后的pyc文件以及1个Excel数据文件目录结构覆盖从建库到业务操作的全流程。目前已有557人学习下载代码经测试运行成功可直接部署使用。对于基础较好的学习者还可以基于现有结构扩展功能模块或参考其数据库设计思路独立完成课程作业或毕业设计的初期立项演示。1. 医院管理系统课设源码为什么先跑 SQL 再碰 Python 才不会翻车计算机相关专业的数据库课设十份里有八份是某个管理系统的增删改查而医院管理系统又是其中最常被选的方向。今年这个基于 Python 和 MySQL 的医院管理系统源码包文件结构很规整一个 hospital.py 控制台入口、四个 SQL 脚本、一个 data.xlsx 数据文件再加上 dbConnector、dataSearcher、dataOperator 等一批按职责拆分的模块。我拆完第一反应是——这包比大多数课设代码靠谱因为它的核心思路是数据和代码分离SQL 先于代码执行。但这恰恰也是新手最容易翻车的地方你打开 hospital.py 直接运行大概率报 1045 或者 1146不是因为代码写错而是数据库还没初始化。这套系统的正确打开方式是把 hospital init.sql、hospital triggers.sql、hospital data insert.sql、hospital others.sql 按顺序导入 MySQL再把 dbConnector.py 里连接参数改成你本机的账号密码最后才轮到 Python 上场。适合正在做数据库课程设计、想复用这套源码改成自己毕设、或者纯粹想学 Python MySQL 如何配合的人。2. 读懂源码结构再动手入口、连接层和数据初始化脚本的执行顺序拿到压缩包先别急着解压运行花五分钟看一下文件命名就能猜出这个课设的完整逻辑。hospital.py 是控制台主程序dataInitiator.py 管数据初始化dbConnector.py 管数据库连接dataSearcher.py 和 dataOperator.py 分别管查询和增删改dataReader.py 负责读取外部数据文件dataDictionary.py 用来生成数据字典。另外还有 mysql01.py、mysql02.py、mysql03.py 三个脚本常见做法是零散的验证脚本——比如分别验证建库、连库、跑一条多表查询用来演示给老师看。这种一个入口、多个职责模块的结构比把所有代码堆在一个文件里的课设要容易答辩得多。你可以在台上按顺序讲数据怎么初始化、连接怎么复用、查询和操作怎么分离老师听着也舒服。2.1 启动之前的准备工作装对 Python 和 MySQL 的版本这个包里的 pyc 文件标的是 cpython-39也就是说当时开发环境是 Python 3.9我一般建议你本地装 3.8 到 3.10 之间的版本都不会有兼容性问题。MySQL 方面如果机器上还没有数据库装 MySQL 8.0 就行如果你用的是 5.7 也完全没问题后面触发器和 utf8mb4 字符集在两个版本下都支持。真正需要留意的是 pymysql 这个库的版本太低的话连 MySQL 8.0 默认的 caching_sha2_password 认证方式会失败安装时用较新的 pymysql 即可规避。连接参数集中在数据库模块里这样主程序不用关心底层连的是本机还是远程库。下面是一个典型的连接函数写法和你包里的 dbConnector.py 逻辑一致import pymysql def get_connection(): # 这里四个参数就是坑最多的地方host 别写 localhost 以外的值 conn pymysql.connect( hostlocalhost, # 本机连接用 localhost 或 127.0.0.1 userroot, # 换成你自己 MySQL 的用户名 password123456, # 换成你自己的密码 databasehospital, # 这个库要先通过 SQL 脚本创建 charsetutf8mb4, # 不写 utf8mb4中文插入很容易变问号 port3306, # MySQL 默认端口改了才需要调整 autocommitFalse # 手动控制事务数据错了还能 rollback ) return conn确认连得上之后再用cursorclasspymysql.cursors.DictCursor去拿字典类型的结果这样后面做控制台输出和格式化会方便很多。参数这块最常被忽略的是charsetutf8mb4很多人只在建库语句里写了字符集连接层没写结果 Python 插入中文照样乱码。2.2 初始化脚本的正确执行顺序init 在前触发器次之数据最后包里的四个 SQL 脚本分别叫 hospital init.sql、hospital triggers.sql、hospital data insert.sql、hospital others.sql从名字就能看出执行顺序。init.sql负责建库建表triggers.sql创建触发器data insert.sql导入基础数据others.sql放的是剩下的索引、视图或者额外的演示查询。顺序错了就会报表不存在或者触发器依赖的列不存在。导入脚本我会用 MySQL 命令行客户端而不是图形化工具因为能看到每条语句的执行结果和报错上下文# 先登录 MySQL然后手动建库如果 init.sql 里没有 CREATE DATABASE 的话 mysql -u root -p # 登录进去之后依次执行 source /path/to/hospital init.sql; source /path/to/hospital triggers.sql; source /path/to/hospital data insert.sql; source /path/to/hospital others.sql;用source而不是复制粘贴的原因是可以一条条看到 OK 和报错信息。如果某条语句报错它的行号会直接暴露问题比如 1064 语法错误十有八九是字符集不匹配或者某个注释里的特殊字符没处理好。三个脚本全部执行后用SHOW TABLES;检查一下表是否齐全再随便SELECT * FROM patient LIMIT 5;看看数据有没有导进去。2.3 主程序启动失败时怎么定位把入口报错拆成三类将 dbConnector.py 的密码改成你自己的直接python hospital.py启动。如果这一步报错大概率是三类问题第一类连接失败报 1045 或 2003说明密码错或 MySQL 服务没起来第二类是查询的表不存在说明 SQL 脚本没导入完或者导入顺序不对第三类是 ModuleNotFoundError比如说 pymysql 没装执行pip install pymysql补上即可。这三类问题里第一类最多。很多人以为代码里的密码就是当初安装 MySQL 时的密码其实很多时候你装 MySQL 时设置了临时密码后来又改了代码却没同步更新。所以我的习惯是先单独写一个两行的 Python 脚本测试连接连上了再去跑主程序这样能快速区分是配置问题还是业务代码问题。3. 数据库设计拆解表结构、数据字典与触发器脚本的答辩价值医院管理系统的表设计通常围绕两个核心对象展开人和钱。人指的是科室、医生、患者钱指的是挂号、诊断、药品费用。这套源码里的 init.sql 应该会覆盖科室表、医生表、患者表、药品表、挂号记录表、收费记录表这几张基础表表与表之间通过外键关联比如医生表通过 dept_id 关联科室表挂号记录表通过 patient_id 和 doctor_id 分别关联患者和医生。这种设计的答辩价值很高因为老师会问为什么要有这么多张表你可以回答为了减少数据冗余患者只存一次基本信息挂号记录里只存患者 ID查询时用 JOIN 把数据拉出来。哪怕只是把这段逻辑复述一遍也比那些所有字段堆在一张表里的课设强很多。3.1 从 dataDictionary.py 看元数据读取直接生成报告里的数据字典数据库课设报告里有一页叫数据字典很多学生是手工把每个字段抄进 Word 里的既费时又容易抄错。dataDictionary.py 这个模块解决的就是这件事——它连接 information_schema 数据库把表名、字段名、数据类型、是否为空、默认值、主键信息一次性查出来。这样做还有个好处你改完表结构代码生成的数据字典自动跟着变报告和实际数据库永远对得上。import pymysql def generate_data_dictionary(db_namehospital): conn pymysql.connect( hostlocalhost, userroot, password123456, databaseinformation_schema, charsetutf8mb4 ) cursor conn.cursor() sql SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY FROM COLUMNS WHERE TABLE_SCHEMA %s ORDER BY TABLE_NAME, ORDINAL_POSITION cursor.execute(sql, (db_name,)) # 每行的输出格式可以自己定表格渲染交给 Pandas 或手工拼接都行 for table, col, ctype, nullable, default, key in cursor.fetchall(): print(f{table} | {col} | {ctype} | {nullable} | {default} | {key}) cursor.close() conn.close()查到的主键标志字段在报告里对应主键说明MUL表示普通索引或外键PRI表示主键。写这段代码的目的不是让你照抄而是告诉你一个思路数据库课设的数据字典完全可以自动化别在这上面耗一晚上。3.2 触发器脚本单独成一个文件为什么要用触发器而不是应用层逻辑医院的挂号记录表有个典型场景每次插入一条挂号记录都要同步更新号源余量或者自动落一条操作日志。这个逻辑放在 Python 业务代码里也能做但放在触发器里更符合课设要求因为你可以在答辩时明确说我用数据库自身的机制保证了一致性即使绕过 Python 直接往库里 INSERT 数据依赖的字段也会自动更新。包里的 triggers.sql 大概率写的就是这类逻辑。我帮你补一个常见示例——挂号时自动把创建时间写进记录表DELIMITER // CREATE TRIGGER trg_registration_before_insert BEFORE INSERT ON registration FOR EACH ROW BEGIN SET NEW.create_time NOW(); END// DELIMITER ;DELIMITER //的作用是临时把语句分隔符改成//因为触发器体内部的;不能直接结束整个 CREATE 语句。当初写这个脚本的人把它单独拎出来说明他踩过这个坑如果你用图形化工具直接粘贴含存储过程或触发器的 SQL经常会因为分隔符问题报错。导入后可以用SHOW TRIGGERS;验证触发器是否注册成功这是答辩时一个很好的加分演示。3.3 表结构设计里容易被老师追问的三个点老师提问往往不在增删改查上而在设计合理性上。第一患者表为什么用身份证号做唯一索引而不是患者 ID 做主键——实务做法是患者 ID 做自增主键身份证号加 UNIQUE 约束因为有些老患者可能没有身份证或者身份证信息有误。第二价格字段用什么类型——药品单价建议用 DECIMAL(10,2)别用 FLOAT因为浮点数有精度问题收费计算时会出现 0.1 0.2 不等于 0.3 的玄学情况。第三外键要不要建——课设里建外键能展示关联完整性但生产环境一般不用物理外键方便分库分表和拆服务这段差异讲清楚老师会认为你有实际项目认知。4. 数据导入与查询模块从 data.xlsx 到 MySQL 的整条链路包里有个 data.xlsx它存在的意义是让基础数据不直接写在 SQL 里而是由外部文件准备好再通过 dataReader.py 读取并写入数据库。这种做法的好处是清洗数据更方便——你可以直接在 Excel 里改科室名称、调整药品价格改完重新导入就行。关键环节这个概念很常见数据导入也是最容易出问题的一段。4.1 dataReader 读 xlsx 再交给 dataOperator 入库的设计意图如果这两步分开理解整个模块就清楚了dataReader 只负责从文件读数据dataOperator 只负责把数据写进数据库。你在答辩时可以讲这样设计让两个模块能独立测试——文件格式变了只改 reader入库逻辑变了只改 operator互不影响。下面是一个精简的实现import pymysql import openpyxl # 读取 xlsx 用这个库包里面应该有对应依赖 def read_department_from_xlsx(file_path): wb openpyxl.load_workbook(file_path) sheet wb[科室] # 按 sheet 名读sheet 名别随便改 rows [] for row in sheet.iter_rows(min_row2, values_onlyTrue): # 第一行一般是表头 if row[0] is None: # 空行直接跳过不用抛异常 continue rows.append(row) return rows def insert_departments(rows): conn get_connection() cursor conn.cursor() sql INSERT INTO department (dept_id, dept_name, location) VALUES (%s, %s, %s) cursor.executemany(sql, rows) # 批量插入比单条 execute 快很多 conn.commit() cursor.close() conn.close()executemany是批量插入的关键一次传入几百条数据比循环execute快一个数量级。如果你是拿来改成自己的课设只改INSERT语句的表名和字段顺序就可以了注意%s占位符的数量必须和 VALUES 里的列数一致多了少了都会报参数数量不匹配的错误。4.2 你拿到的 xlsx 不一定能直接导入三个常见的数据质量问题第一个问题Excel 里可能有合并单元格合并区域只有左上角有值其余是空值导入时就缺数据。第二个问题日期列在 Excel 里是日期格式Python 读出来是 datetime 对象往 MySQL 日期类型里插没问题但如果你在 Excel 里把2024/1/5填成2024.1.5就会变成字符串入库后一切查询都乱套。第三个问题身份证号超过 15 位会被 Excel 自动显示成科学计数法在实际数据里常见的是尾部变成 000一旦入库就再也恢复不出来。我的处理习惯是先不用 openpyxl 直接读原文件而是把 xlsx 另存为 CSV 后用文本编辑器打开检查一遍看哪些字段被 Excel 悄悄改了格式。发现问题后把有问题的列在 Excel 里设成纯文本格式再重新录入然后再保存成 xlsx 或 CSV 给 reader 读。这个过程本身就是课设报告里数据处理章节的素材。4.3 dataSearcher 按条件查数据的两种姿势等值查询和模糊查询控制台管理系统的查询模块一般就两种需求精确查和模糊查。精确查典型场景是按患者 ID 直接调出病历模糊查典型场景是输入姓氏找患者或者按科室名称筛选医生。dataSearcher.py 里大概率就是这两个函数的封装。我用参数化查询的方式给你做个参考import pymysql def search_patients(name_keywordNone, dept_idNone): conn get_connection() cursor conn.cursor(pymysql.cursors.DictCursor) conditions [] params [] if name_keyword: conditions.append(patient_name LIKE %s) params.append(f%{name_keyword}%) if dept_id: conditions.append(dept_id %s) params.append(dept_id) # 不是拼接字符串是拼接条件片段SQL 注入的风险完全规避掉 where_sql AND .join(conditions) if conditions else 11 sql f SELECT patient_id, patient_name, gender, phone FROM patient WHERE {where_sql} ORDER BY patient_id DESC cursor.execute(sql, params) results cursor.fetchall() cursor.close() conn.close() return results上面这段代码里LIKE %s配合%keyword%是模糊查询的标准姿势而条件片段拼接可防 SQL 注入因为参数是被 pymysql 转义后传进去的不会直接被当成 SQL 执行。ORDER BY patient_id DESC 让新登记的记录排前面控制台输出时更贴近日常使用习惯。如果你想扩展加一个日期范围查询也照这个模式来就行。5. 课设源码避坑指南六条亲测有效的排查记录这个包我在拆解和重新部署的过程中遇到了一些问题按现象 → 原因 → 解决的方式记录在下面。每一条都是实际会碰到的不是理论推演。5.1 连接报错 2059Authentication plugin caching_sha2_password cannot be loaded现象运行连接脚本报 2059 错误提示认证插件无法加载。原因MySQL 8.x 默认的用户认证插件是 caching_sha2_password老版本的 pymysql 只支持 mysql_native_password双方握不上手。解决两个方案选一个就行。要么升级 pymysql 到较新版本直接在终端执行pip install --upgrade pymysql要么把 MySQL 用户的认证方式改成旧协议执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;。改完之后再试连接这一步做完通常问题就消失了。5.2 导入 SQL 报 1064语法错误但你看不出是哪句坏了现象执行 hospital triggers.sql 时报语法错误错误信息指向某条语句但这句 SQL 看起来没毛病。原因触发器或存储过程内部有分号MySQL 命令行会把它当成语句结束。你没加DELIMITER //的话从第一个分号处就断了。解决确认脚本开头有没有DELIMITER //结尾有没有DELIMITER ;。如果原脚本没有在命令行里手动执行DELIMITER //再 source 这个文件导入完执行DELIMITER ;。图形化工具导这种文件也容易踩最好就用命令行 source。5.3 中文插入变成问号数据进去了utf8mb4 字符集没全链路打通现象从 Python 插入患者姓名查出来是???。原因建库时指定了 utf8mb4但连接层 charset 参数没写或者表本身是 latin1 字符集。解决从库到表到连接三点全部统一新建库用CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci建表语句里也带DEFAULT CHARSETutf8mb4Python 连接处加上charsetutf8mb4。三处都改了之后把有问题的数据删掉重新插一遍别指望已经存进去的问号能自动恢复。5.4pycache干扰改了代码但运行结果还是旧的现象修改了 dataSearcher.py 或 dataOperator.py 后重新运行 hospital.py行为没变化看起来像没保存。原因Python 会把编译后的 .pyc 缓存到__pycache__目录如果你改的是 .py 文件、但进程之前已经导入了旧模块或者你误改了同名的其他副本那运行用的就是缓存里的旧代码。解决删除整个__pycache__目录再运行或者用python -B hospital.py暂时禁用字节码缓存。如果你同时修改了多个同名文件检查一下你编辑的路径是不是 hospital.py 实际 import 的那份。5.5 data.xlsx 导进去少了几行Excel 的合并单元格和空行现象用 dataReader 读 xlsx 再入库最终 count 出来的记录数比 Excel 里肉眼看到的少。原因Excel 里存在合并单元格——合并区域只有第一个格子有值其余格子是None代码跳过空行了或者表格最下方有几行你看不到的残留格式。解决先把数据另存为 CSV用文本编辑器复核行数再清洗掉空行和格式残留。如果代码逻辑跳到空行就 continue建议改成打印日志看看跳过了哪些行避免误伤有效数据。5.6 manual 执行事务后忘记 commit控制台看起来没反应但库里没数据现象dataOperator 执行 INSERT 或 UPDATE 后返回结果看起来正常打开 MySQL 一看没有变化。原因dbConnector 里 autocommitFalse你需要手动 commit。如果代码里只在删除、更新这种操作后 commit但插入逻辑漏了就会出现这种假成功。解决在连接参数里可以临时设置autocommitTrue验证但正式逻辑建议保持手动事务在每次写操作完成后显式调用conn.commit()一旦发现数据异常用conn.rollback()回滚。这个习惯在任何 Python MySQL 的项目里都通用。6. 把控制台系统改成 Web 界面复用既有模块的最小升级路径课设答辩时老师对控制台程序的印象分通常不如网页系统因为控制台界面看不到输入框和列表交互感弱。但你不需要重写整个系统——模块化设计的优势在这里就体现了。dbConnector 的连接函数、dataSearcher 的查询函数、dataOperator 的写操作函数全部可以复用你只需要加一个 Flask 壳。最小改造方案是拆两层第一层新建一个web.py内部导入你现有的搜索和数据操作模块第二层给每个函数配一个路由用模板渲染页面。下面这个示例展示怎么把按姓名查患者的逻辑暴露成一个网页接口from flask import Flask, request, render_template from dataSearcher import search_patients # 直接复用原来的查询函数 app Flask(__name__) app.route(/, methods[GET, POST]) def index(): patients [] if request.method POST: name request.form.get(name, ) # 这里传 None 表示不筛选科室只按姓名模糊搜索 patients search_patients(name_keywordname, dept_idNone) return render_template(index.html, patientspatients) if __name__ __main__: app.run(host127.0.0.1, port5000, debugTrue)页面模板也不用做得复杂一个表单加一个表格就够了。前端不在课设评分权重里但能从浏览器访问这个事实本身就比控制台高一个维度。需要注意的只有一点这个系统原本是同步控制台交互改成 Web 端之后原本那些input()接收参数的位置全部要换成从request.form或 URL 参数里拿——好在你包里的 searcher 和 operator 已经把参数都收拢到函数里了改动范围集中在入口层。我在拿到这套源码时干的第一件事不是打开 hospital.py 看主程序逻辑而是把四个 SQL 脚本先按顺序跑了一遍确认表和数据都就位然后把连接层密码改成本机配置再启动控制台。整个过程花了不到十分钟。从那以后我每次接手课设源码都强制自己先摸清哪部分是数据、哪部分是代码、连接从哪进来再决定从哪开始改希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Atlas 300V部署YOLO模型实战:从环境搭建到推理优化全攻略 1. 项目概述:Atlas不是一张普通显卡,而是一套国产AI算力底座先回答那个热词问题:Atlas 300V 24G确实是运算加速卡,但它不是显卡。很多人第一次接触Atlas都会拿它跟NVIDIA的显卡做类比,然后配置环境时发现完全不是一回事… · 2026/9/25 22:31:50
PHP图像处理之轻松搞定缩放裁剪水印滤镜 一、前言在 Web 开发中,图片处理是不可或缺的技能。无论是用户头像上传、商品图片展示,还是社交媒体分享图生成,都需要对图片进行各种处理。PHP 作为最流行的后端语言之一,提供了强大的图片处理能力。本文将带你全面掌握 PHP 图片… · 2026/9/25 22:31:50
exit code 0是假胜利?一文搞懂进程退出码与排障方法 写代码这几年,几乎每天都会在开发工具下方看到一行绿色的小字:Process finished with exit code 0。第一次见到它的时候我还是个刚学编程的小白,心里想的是:这行字到底什么意思?是程序没问题了,还是它在跟我… · 2026/9/25 23:07:20
中文法律大模型实战:从基座选择到RAG增强的部署避坑指南 简介:LexiLaw是一款面向中文法律领域微调的大语言模型资源包,基于ChatGLM-6B架构,针对法律条款解读、案例分析、法规咨询等任务优化。适合法律科技开发者、NLP研究者和法律专业学生快速搭建智能问答原型,解决通用模型在法律场景下… · 2026/9/25 23:07:07
Teigha4 .NET读写DWG:不装AutoCAD也能解析图纸 简介:Teigha(原名OpenDwg/DWGdirect)是脱离AutoCAD环境读写DWG文件的经典开发库,本资源面向.NET平台二次开发人员,以VB.net和C#双语言源码演示了不启动AutoCAD即可提取图形数据的实现思路。压缩包共165个文件、约61.5M… · 2026/9/25 23:06:34
统信UOS内网离线安装Flash插件全流程与避坑指南 简介:针对统信UOS内置浏览器无法加载Flash插件、且内网环境阻碍在线安装的问题,这份资源打包了一套离线安装与排错方案,主要面向政企运维人员、UOS普通用户及系统管理员,帮助恢复旧式Flash网页内容的正常显示。资源包共6个文件&am… · 2026/9/25 23:06:34
阳光板厂推荐 银川君瑞祥新材料科技质量参考评选 在工业厂房搭建、农业温室建设、体育场馆改造以及化工车间升级的各类工程项目中,采光板材的选择,从来都是影响项目整体质量、后期运维成本与使用安全的核心环节。面对西北区域强紫外线、大温差、多风沙的特殊气候,不少项目都曾踩过通用款采光… · 2026/9/25 23:06:27
基于PHP的H5转APP在线封装打包平台实现与避坑指南 简介:面向需要把H5手机网站快速封装成安卓和苹果安装包的开发者,这套PHP源码以在线打包方式提供免签绿色封装方案,支持Android与iOS平台。可自行上传安卓证书和启动图,并针对iOS 14全屏兼容问题做了专门修复;同时去除多… · 2026/9/25 23:06:21
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37