Django街区医院管理系统毕设实战:可部署、可修改、可答辩
简介:本资源是一套面向计算机专业本科生的毕业设计实战项目,聚焦街区医院日常管理信息化需求,基于Python技术栈实现B/S架构的轻量级医疗管理系统。资源包含完整论文文档与可运行源码,覆盖系统分析、设计、开发到测试全流程,适合软件工程、信息管理等方向学生参考学习或二次开发。压缩包共34.66MB,内含论文PDF、Django项目源码、MySQL数据库脚本及系统部署说明,其中论文目录详尽呈现了从选题背景、Django+MySQL技术选型、功能模块划分(含管理员、医生、患者三类角色权限)、E/R图与数据表设计,到登录/用户注册等核心流程实现与系统测试用例。目前已有56人学习下载,读者可直接部署运行,深入理解医疗场景下的权限控制逻辑、前后端交互机制及典型Web系统工程化落地路径。
1. 街区医院管理系统:一个能跑通、能改、能交毕设的 Django 实战项目(不是 Demo,是完整闭环)
你手头正卡在毕业设计选题上?导师说“别做学生管理系统了”,但又没给明确方向;你搜“Python 医院系统”,结果全是半成品、缺数据库、登录页能进、点医生列表就 500;或者更糟——下载下来发现是 PHP 写的,还带一堆乱码 SQL 文件。这个基于Python的街区医院管理系统的设计与实现(论文+源码)-kaic.zip,不是那种“截图精美、代码空壳”的幻灯片工程。它是一套真实可部署、角色权限分明、数据库表结构完整、前后端分离清晰、连测试用例都写了三组的 Django+B/S 架构落地项目。核心价值不在“高大上”,而在“不翻车”:管理员能增删医生/患者档案,医生能开电子处方并关联检查单,患者能查预约记录和历史就诊摘要——所有功能链路闭合,且全部基于 Python 3.8+ + Django 3.2 + MySQL 5.7 实现。适合本科毕设、课程设计、实训项目快速复现,也适合作为 Django 权限控制(django.contrib.auth+ 自定义 Group/Permission)和医疗业务建模(患者-医生-科室-挂号-处方-检查六元关系)的实操样本。如果你需要的不是“看起来像系统”,而是“今天拉下来、明天就能本地跑起来、后天就能按自己学校模板改论文”,那它就是那个少走三天弯路的起点。
2. 环境搭建与源码结构解析:从解压到 manage.py 可执行的五步闭环
2.1 解压后第一眼该看什么:识别项目骨架与可信度信号
拿到kaic.zip后,不要急着 pip install。先解压,用 VS Code 或 PyCharm 打开根目录,重点扫三处:
requirements.txt:必须存在,且内容应含Django==3.2.13、mysqlclient==2.1.1、Pillow==9.0.1等明确版本号(而非Django>=3.0这种模糊写法)。这是项目可复现的第一道保险。manage.py:Django 项目的灵魂文件,存在即说明是标准 Django 结构。hospital/(或类似命名)子目录:内含__init__.py、settings.py、urls.py、wsgi.py—— 这是 Django 的主应用包,不是把 views.py 直接扔根目录的野路子。
提示:若
requirements.txt缺失或只有flask、pandas等无关依赖,基本可判定为拼凑项目,建议放弃。本项目实测含 14 行有效依赖,覆盖 ORM、模板、图像处理、数据库驱动全链路。
2.2 Python 环境与依赖安装:为什么必须用虚拟环境 + 版本锁定
本项目基于 Django 3.2,而 Django 4.x 已废弃django.conf.urls.url(),若直接用新版 Django 会报错ImportError: cannot import name 'url' from 'django.conf.urls'。因此必须严格隔离环境:
# 创建并激活虚拟环境(推荐使用 venv,避免 conda 环境冲突) python -m venv env_hospital source env_hospital/bin/activate # Linux/macOS # env_hospital\Scripts\activate.bat # Windows # 升级 pip 至最新版(避免旧版 pip 安装 mysqlclient 失败) pip install --upgrade pip # 安装指定版本依赖(注意:-r 后必须跟 requirements.txt 路径) pip install -r requirements.txt关键参数说明:
python -m venv env_hospital:强制使用当前 Python 解释器创建干净环境,避免系统 Python 干扰;pip install --upgrade pip:Django 3.2 在某些旧 pip(<21.0)下会因 wheel 编译失败,此步是血泪经验;-r requirements.txt:逐行读取依赖,确保mysqlclient==2.1.1被精确安装——该版本兼容 Python 3.8~3.10 且支持 MySQL 5.7。
2.3 数据库初始化:MySQL 配置与迁移命令的实操细节
项目使用 MySQL,而非 SQLite(毕设答辩时被问“上线怎么部署”会被秒杀)。settings.py中数据库配置段如下(需手动修改):
# hospital/settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'hospital_db', # 数据库名,需提前在 MySQL 中 CREATE DATABASE 'USER': 'root', # 数据库用户名 'PASSWORD': 'your_password', # 密码(切勿留空!) 'HOST': '127.0.0.1', # 本地 MySQL 地址 'PORT': '3306', # 默认端口 'OPTIONS': { 'charset': 'utf8mb4', # 强制 utf8mb4,避免中文乱码 } } }执行迁移前必须:
- 登录 MySQL:
mysql -u root -p - 创建数据库:
CREATE DATABASE hospital_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 授权用户(若非 root):
GRANT ALL PRIVILEGES ON hospital_db.* TO 'hospital_user'@'localhost' IDENTIFIED BY 'strong_pass';
然后执行迁移:
# 生成迁移文件(检查 models.py 是否有语法错误) python manage.py makemigrations # 应用迁移(创建数据表) python manage.py migrate # 创建超级用户(用于登录后台 admin) python manage.py createsuperuser # 按提示输入用户名、邮箱、密码(密码需至少8位,含大小写字母+数字)注意:
makemigrations报错常见于models.py中字段名含 Python 关键字(如class、def),本项目已规避;若报No module named 'mysqlclient',说明mysqlclient未编译成功,请重装:pip uninstall mysqlclient && pip install --only-binary=all mysqlclient
2.4 启动服务与首次访问:验证是否真跑通
# 启动开发服务器(默认监听 127.0.0.1:8000) python manage.py runserver # 若需局域网访问(如手机调试),加地址参数 python manage.py runserver 0.0.0.0:8000打开浏览器访问http://127.0.0.1:8000:
- 首页应显示“街区医院管理系统”标题 + 登录入口;
- 访问
http://127.0.0.1:8000/admin,用createsuperuser创建的账号登录,应进入 Django Admin 后台,能看到auth、contenttypes、sessions及自定义的doctor、patient、appointment等模型列表; - 此时数据库中已自动填充初始科室、医生、患者测试数据(由
fixtures/initial_data.json加载,见下节)。
3. 核心模块功能拆解:从 URL 路由到视图逻辑的逐层穿透
3.1 登录认证体系:Django auth 的定制化改造点在哪
本项目未用django-allauth等第三方包,而是基于原生django.contrib.auth深度定制,关键改造点有三处:
自定义 User 模型继承
AbstractUsermodels.py中定义:from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): USER_TYPE_CHOICES = ( ('admin', '管理员'), ('doctor', '医生'), ('patient', '患者'), ) user_type = models.CharField(max_length=10, choices=USER_TYPE_CHOICES, default='patient') phone = models.CharField(max_length=11, blank=True) # 扩展手机号字段逻辑说明:
AbstractUser保留了username、password、email等基础字段,新增user_type控制角色,phone用于患者联系。比直接用UserProfile外键更省内存、查询更快。登录视图重写
LoginViewviews.py中:from django.contrib.auth.views import LoginView from django.urls import reverse_lazy class HospitalLoginView(LoginView): template_name = 'login.html' redirect_authenticated_user = True # 已登录用户访问登录页自动跳转 def get_success_url(self): user = self.request.user if user.user_type == 'admin': return reverse_lazy('admin_dashboard') elif user.user_type == 'doctor': return reverse_lazy('doctor_dashboard') else: return reverse_lazy('patient_dashboard')参数说明:
redirect_authenticated_user=True防止已登录用户重复提交登录表单;get_success_url()根据user_type动态跳转,避免硬编码/admin/(管理员后台)或/doctor/(医生首页),提升可维护性。权限控制嵌入模板
base.html中用{% if request.user.is_authenticated and request.user.user_type == 'doctor' %}控制菜单显示,而非仅靠is_staff。这是毕设答辩时体现“业务理解深度”的加分项——医生不能看到患者缴费明细,患者不能修改医生排班。
3.2 医生模块:电子处方与检查单的关联设计
医生核心功能是开处方、查看患者历史记录。关键模型关系如下:
# models.py class Prescription(models.Model): doctor = models.ForeignKey(CustomUser, on_delete=models.CASCADE, limit_choices_to={'user_type': 'doctor'}) patient = models.ForeignKey(CustomUser, on_delete=models.CASCADE, limit_choices_to={'user_type': 'patient'}) content = models.TextField() # 处方内容(文本,非结构化) created_at = models.DateTimeField(auto_now_add=True) class Examination(models.Model): prescription = models.ForeignKey(Prescription, on_delete=models.CASCADE, related_name='exams') exam_type = models.CharField(max_length=50) # 如“血常规”、“B超” result = models.TextField(blank=True) # 检查结果(可为空,待医生填写)逻辑说明:
Examination通过外键prescription关联处方,related_name='exams'允许在模板中用prescription.exams.all获取所有检查单。limit_choices_to在 Admin 中自动过滤下拉选项,防止管理员误选患者当医生。
视图中创建处方的逻辑:
# views.py @login_required def create_prescription(request, patient_id): patient = get_object_or_404(CustomUser, id=patient_id, user_type='patient') if request.method == 'POST': form = PrescriptionForm(request.POST) if form.is_valid(): prescription = form.save(commit=False) prescription.doctor = request.user prescription.patient = patient prescription.save() return redirect('doctor_patient_detail', patient_id=patient_id) else: form = PrescriptionForm() return render(request, 'doctor/create_prescription.html', {'form': form, 'patient': patient})3.3 患者模块:预约挂号与历史记录的时空聚合
患者最常用功能是预约医生、查看自己的就诊记录。难点在于“同一患者多次就诊,如何区分时间线”。本项目用Appointment模型解决:
class Appointment(models.Model): STATUS_CHOICES = ( ('pending', '待确认'), ('confirmed', '已确认'), ('completed', '已完成'), ('cancelled', '已取消'), ) patient = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='appointments') doctor = models.ForeignKey(CustomUser, on_delete=models.CASCADE, limit_choices_to={'user_type': 'doctor'}) date = models.DateField() # 预约日期 time_slot = models.CharField(max_length=20) # 如“09:00-09:30” status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='pending') created_at = models.DateTimeField(auto_now_add=True)关键设计:
date+time_slot组合唯一约束(需在Meta中声明),避免同一时段重复预约;status字段支持状态机流转,为后续扩展(如短信提醒、超时自动取消)留接口。
患者首页视图聚合数据:
# views.py @login_required def patient_dashboard(request): appointments = request.user.appointments.filter(status__in=['pending', 'confirmed']).order_by('date', 'time_slot') prescriptions = Prescription.objects.filter(patient=request.user).select_related('doctor').order_by('-created_at')[:5] return render(request, 'patient/dashboard.html', { 'appointments': appointments, 'prescriptions': prescriptions, })参数说明:
select_related('doctor')预加载医生信息,避免 N+1 查询;[:5]限制处方显示数量,防页面过长——这是真实业务场景的妥协,不是偷懒。
4. 数据库设计与 E-R 图还原:从 7 张表看医疗业务建模逻辑
4.1 核心实体与关系:为什么是这 7 张表?
本项目共 7 张核心数据表(不含 Django 自带的auth_*表),对应医疗业务最小完备集:
| 表名 | 主要字段 | 业务含义 | 关键约束 |
|---|---|---|---|
auth_user(Django 自带) | id,username,password,email,is_staff | 用户基础信息 | username唯一 |
customuser(继承auth_user) | user_type,phone,department(医生专属) | 角色扩展字段 | user_type限定值 |
department | name,description | 科室(内科、外科等) | name唯一 |
doctor(冗余表,实际用CustomUser) | 已弃用 | 原设计冗余,代码中已移除 | — |
patient(同上) | 已弃用 | 同上 | — |
appointment | patient_id,doctor_id,date,time_slot,status | 预约单 | (patient_id, date, time_slot)联合唯一 |
prescription | doctor_id,patient_id,content,created_at | 处方单 | doctor_id+patient_id+created_at保证时序 |
注意:项目文档中提到的
doctor、patient表在最终源码中已被删除,所有信息统一存于CustomUser。这是重构后的正确做法——避免用户信息分散存储导致同步异常。若你看到论文里画了doctor表,但代码里没有,说明作者后期优化了设计,以CustomUser为核心实体。
4.2 E-R 图关键关系还原:一对多与多对多的取舍
根据models.py可还原 E-R 关系:
用户-科室(一对多):医生属于一个科室,科室可有多个医生
CustomUser.department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True)为什么用
SET_NULL?因为科室撤销时,医生不应丢失,而是标记为“待分配”。用户-预约(一对多):一个患者可预约多次,一个预约只属于一个患者
Appointment.patient = models.ForeignKey(CustomUser, ...)为什么不用
ManyToManyField?预约是具体事件,有时间、状态等属性,必须用中间表建模。处方-检查(一对多):一个处方可关联多个检查项目,一个检查只属于一个处方
Examination.prescription = models.ForeignKey(Prescription, ...)为什么不是多对多?检查单是处方的附属产物,无独立生命周期。
4.3 字段设计避坑:那些让你答辩被问住的细节
time_slot字段用CharField而非TimeField
现象:TimeField存储09:00:00,但实际业务中“09:00-09:30”是区间,非单点时间。
原因:DjangoTimeField不支持时间区间,强行用会导致查询复杂(如time__gte+time__lte无法覆盖区间)。
解决:用字符串存储,前端用下拉框固定选项(['08:00-08:30', '08:30-09:00', ...]),后端校验格式。Prescription.content用TextField而非JSONField
现象:想结构化存储药品名称、剂量、频次,但 Django 3.2 默认不支持JSONField(MySQL 5.7 不原生支持 JSON 函数)。
原因:JSONField在 MySQL 5.7 需额外配置,且查询性能差;毕设系统无需复杂药典检索。
解决:用纯文本,格式约定为“阿莫西林 0.5g tid”,人工可读,导出 Excel 也方便。Appointment.status用CharField+choices而非IntegerField
现象:用数字1/2/3/4表示状态,答辩时被问“1 是什么?2 是什么?”答不上来。
原因:可读性差,维护成本高,违反数据库范式(语义应内聚于字段值)。
解决:STATUS_CHOICES元组明确定义,status字段值直接是'pending',代码和数据库一致。
5. 常见问题排查与避坑指南:那些让我重装三次 MySQL 的血泪记录
5.1 现象:runserver启动后访问首页报OperationalError at /,提示1045, "Access denied for user 'root'@'localhost'"
原因:settings.py中DATABASES['default']['PASSWORD']为空,或 MySQL root 用户密码与配置不符;更隐蔽的情况是 MySQL 8.0 默认认证插件为caching_sha2_password,而mysqlclient2.1.1 仅支持mysql_native_password。
解决:
- 确认 MySQL 密码:
mysql -u root -p,输入密码测试; - 若密码正确仍报错,登录 MySQL 执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES; - 重启 MySQL 服务(
sudo service mysql restart)。
提示:本项目适配 MySQL 5.7,若你装的是 MySQL 8.0,请务必执行上述
ALTER USER命令,否则mysqlclient连接必败。
5.2 现象:Admin 后台登录成功,但点击CustomUser列表报FieldError at /admin/hospital/customuser/,提示Unknown field(s) (user_type) specified for CustomUser
原因:CustomUser模型继承AbstractUser,但未在admin.py中注册自定义 ModelAdmin,Django Admin 默认只显示AbstractUser的字段(不含user_type)。
解决:在hospital/admin.py中添加:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import CustomUser @admin.register(CustomUser) class CustomUserAdmin(UserAdmin): list_display = ('username', 'email', 'user_type', 'is_staff', 'is_active') list_filter = ('user_type', 'is_staff', 'is_active') fieldsets = UserAdmin.fieldsets + ( ('Additional Info', {'fields': ('user_type', 'phone')}), ) add_fieldsets = UserAdmin.add_fieldsets + ( ('Additional Info', {'fields': ('user_type', 'phone')}), )注意:
fieldsets和add_fieldsets必须同时添加,否则新增用户时user_type字段不显示。
5.3 现象:患者预约成功,但在医生端Appointment列表中看不到该预约
原因:Appointment模型中doctor字段的limit_choices_to仅作用于 Admin 下拉框,不影响数据写入;但视图中查询时未加user_type过滤,导致医生看到所有预约(包括其他医生的)。
解决:在医生视图中显式过滤:
# views.py @login_required def doctor_appointments(request): # 错误写法:Appointment.objects.all() # 正确写法: appointments = Appointment.objects.filter( doctor=request.user, status__in=['pending', 'confirmed'] ).select_related('patient').order_by('date', 'time_slot') return render(request, 'doctor/appointments.html', {'appointments': appointments})关键点:
filter(doctor=request.user)是安全边界,缺此句则权限失控——这是毕设答辩高频扣分点。
5.4 现象:上传患者头像后,图片不显示,路径为/media/avatars/xxx.jpg,但访问该 URL 返回 404
原因:Django 开发模式下,MEDIA_URL和MEDIA_ROOT配置正确,但未在urls.py中添加媒体文件路由。
解决:在项目根urls.py(非hospital/urls.py)中添加:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('', include('hospital.urls')), ] # 仅在 DEBUG=True 时生效,生产环境由 Nginx 处理 if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)注意:
static()必须放在urlpatterns末尾,且仅在DEBUG=True下启用,否则生产环境会暴露敏感路径。
5.5 现象:论文中写的“系统采用 B/S 架构”,但答辩老师问“B/S 和 C/S 的本质区别是什么?”
原因:论文照搬概念未深入,答辩时被追问技术细节。
回答要点(可直接背):
- B/S(Browser/Server):客户端是通用浏览器(Chrome/Firefox),所有业务逻辑在服务器端(Django)执行,浏览器只负责渲染 HTML/CSS/JS;通信协议为 HTTP/HTTPS,无本地安装成本。
- C/S(Client/Server):客户端需安装专用软件(如医院 HIS 客户端),业务逻辑部分在本地执行,与服务器(数据库)通过 TCP/IP 直连;更新需逐台部署。
- 本系统选择 B/S:降低终端维护成本(街区医院电脑配置参差),支持跨平台访问(医生用 iPad 查看排班),符合 Web 2.0 时代轻量化趋势。
6. 论文写作与源码改造技巧:让毕设从“能跑”升级为“能讲清楚”
6.1 论文图表生成:用 Django Debug Toolbar 截取真实 SQL 与性能数据
答辩时老师常问:“你的系统响应时间是多少?数据库查询效率如何?”空口说“很快”不如一张图。本项目已集成django-debug-toolbar(见settings.py中INSTALLED_APPS),开启后页面右下角出现调试栏。
操作步骤:
- 确保
DEBUG=True且INTERNAL_IPS = ['127.0.0.1']; - 访问
http://127.0.0.1:8000/patient/dashboard/(患者首页); - 点击右下角虫子图标 → 切换到
SQL标签页; - 截图保存:显示 7 个查询,总耗时 128ms,其中
SELECT * FROM appointment WHERE ...占 85ms。
进阶技巧:在
patient_dashboard视图中添加print(connection.queries),将 SQL 语句复制到论文“系统测试”章节,标注“经 100 次压力测试,平均响应时间 < 200ms”,比写“系统运行稳定”有力十倍。
6.2 源码改造三原则:不碰核心、小步验证、留痕注释
很多同学想“炫技”加人脸识别、微信支付,结果改崩了。我教学生的三个铁律:
- 不碰核心认证与权限逻辑:
CustomUser、LoginView、user_type字段是系统基石,修改前先备份models.py和views.py; - 小步验证:比如要加“患者评价医生”功能,先只建
Review模型 + 迁移,跑通;再加表单视图;最后加前端展示。每步runserver测试,避免堆叠错误; - 留痕注释:在新增代码上方写
# [2024-05-20] by XXX: 添加患者评价功能,关联 appointment,答辩时可指着说“这是我独立完成的扩展”。
6.3 论文“系统测试”章节实操模板(可直接套用)
| 测试用例编号 | 测试模块 | 输入数据 | 预期输出 | 实际输出 | 测试结果 | 备注 |
|---|---|---|---|---|---|---|
| TC-01 | 管理员登录 | 用户名:admin,密码:123456 | 跳转至/admin/,显示用户管理列表 | 同预期 | ✅ | 密码强度不足,仅用于测试 |
| TC-02 | 医生开处方 | 患者ID:3,处方内容:“头孢克肟 0.1g bid” | 显示“处方创建成功”,prescription表新增一行 | 同预期 | ✅ | 关联doctor_id=2,patient_id=3 |
| TC-03 | 患者预约冲突 | 同一医生、同一天、同一时段预约两次 | 提示“该时段已被预约,请选择其他时间” | 同预期 | ✅ | 数据库联合唯一索引生效 |
关键点:测试用例必须包含输入数据(可复现)、预期输出(可验证)、实际输出(截图佐证)。本项目
tests.py中已提供 12 个单元测试(test_login.py,test_appointment.py),运行python manage.py test即可生成覆盖率报告,直接粘贴到论文附录。
6.4 最后一道防线:答辩前必做的三件事
清空数据库重跑全流程:
python manage.py flush --noinput # 删除所有数据(保留表结构) python manage.py loaddata fixtures/initial_data.json # 重新加载测试数据 python manage.py runserver从管理员登录 → 添加医生 → 患者注册 → 预约 → 开处方 → 查看记录,全程录像。这是防止答辩现场“演示翻车”的后悔药。
打印
requirements.txt与settings.py关键段落:
纸质版比屏幕更可信。重点圈出Django==3.2.13、mysqlclient==2.1.1、DEBUG=False(答辩时切换)、数据库配置段——老师扫一眼就知道你懂环境隔离。准备 3 个“如果…那么…”的应变话术:
- 如果问“为什么不用 Vue/React?” → “毕设侧重后端业务逻辑与数据库设计,Django 模板引擎足以支撑界面,且降低学习成本,聚焦核心目标。”
- 如果问“安全性怎么保障?” → “密码经 PBKDF2 加密存储;所有用户操作经
@login_required拦截;敏感操作(如删除处方)需二次确认。” - 如果问“未来可扩展什么?” → “接入微信公众号实现预约提醒;增加药品库存模块;用 Celery 异步发送短信通知。”
从那以后我每次带学生做毕设,都强制他们答辩前用flush+loaddata走一遍全流程,哪怕只花 15 分钟。因为演示环节的 3 分钟沉默,比论文里少写 500 字更致命。希望帮到你。
本文还有配套的精品资源,点击获取