拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Django在线问诊系统实战:从ORM建模到WebSocket实时推送与大数据分析

Django在线问诊系统实战:从ORM建模到WebSocket实时推送与大数据分析

去年帮一个学弟收拾“Django基于大数据技术的互联网问诊系统”的时候,我第一眼看到的是:博客能跑,注册能走,页面一查,麦说大数据的地方只有一个写着“超大数据中心”的静态图片。我问他的大数据指什么,他想了半天,说数据库里能存几万条患者记录。我没批评他,因为照着网传的速成课赶完的作品,十有八九都是这样。真正伤脑筋的是答辩那关,评阅老师随便问一句“数据从哪来、往哪去、分析之后干了什么”,整个项目就露馅了。

那天起我意识到,这类标题里带着“源码+全套教程打包送”的毕设项目,核心套路并不复杂,但要把每一步讲清楚、做扎实,让系统不仅能跑、能查、能推,还能在答辩现场经得住提问,就值得认真复盘一遍。这篇东西我按完整项目实操来写,从选型、模型、查询、实时推送,到大数据分析怎么落地、源码拿到手怎么改,再到答辩现场最容易被追问的问题,全部过一遍。不管是第一次摸Django的新手,还是已经能写几个页面的同学,这条路径都能直接套用。

1. 项目设计与思路拆解

1.1 为什么在线问诊系统用 Django 最合适

毕设选型首先要回答一个问题:技术栈能不能用最少的时间把业务做完,同时让答辩有得讲。

在线问诊系统不是纯展示型网站,它有真实的业务流:患者注册、医生入驻、预约问诊、填写病历、开处方、诊后评价、消息提醒,还要叠加一部分运营数据看板。这种“快速多张业务表+后台管理+接口交互”的项目,Django几乎是现成的答案。

Django自带Admin后台,这意味着你不用从零写一套管理端界面,医生资料、科室分类、问诊记录都能直接在后台维护。这一点在毕设排期里是巨大的时间红利。其次是Django的ORM,它把数据库操作封装成对象方式,新手不必手写SQL,只需要定义数据模型,就能完成建表和查询。模型相当于数据库表的结构说明,跑一次迁移命令,表就自动生成了。

另一个隐藏优势是Django生态里有大量现成模块:用户认证、权限分组、表单验证、分页、消息框架,几乎覆盖了一个课程设计百分之七十的基本需求。与其开着Spring Boot的配置地狱,或者用Flask自己组装中间件,不如一套Django全拎走,把精力放到业务和大数据链路上。

如果你愿意更进一步,用Django Unfold这类后台美化方案,还能给管理界面加分。很多免费源码项目只给你一个默认的Django admin,稍显朴素。答辩时老师看到清爽的定制后台,印象分会明显不一样。

1.2 大数据不是一个概念,而是一条数据链路

“基于大数据技术”这几个字,经常被人当成一句装饰。实际上在毕设里,它应该是完整的数据处理链路:采集、存储、清洗、分析、可视化、辅助决策。

放到问诊系统里,具体是这样:

  • 采集层:用户有哪些行为?什么时候登录、搜索了什么症状、浏览了哪个医生主页、咨询了多长时间、提交了哪些表单。
  • 存储层:业务数据进MySQL或PostgreSQL,行为日志和行为明细可以单独建表,方便后续分析。
  • 清洗层:把空字段、异常值、重复提交记录处理掉,比如把时间戳统一格式,把“未知性别”归一化。
  • 分析层:用Pandas做快速统计,或者用Spark跑离线任务,计算出高峰时段、热门科室、医生负载、病情分布等指标。
  • 展示层:把分析结果用ECharts或Grafana做成图表,放进数据大屏页面。

你无需真的搭三台节点的Hadoop集群,那对本科毕设来说是巨大的运维负担。更合理的做法是把“大数据技术原理”用在合适的位置:用Spark做一次离线分析,用Pandas做数据预处理,用Redis做缓存和实时推送的消息中间件。答辩的核心是讲清楚链路,而不是吹集群规模。

这也是我后来帮他重构时反复说的:数据链路通了,技术的价值就显出来了。你不需要每一次查询都走Spark,但你要让评委看到你知道分析型任务和事务型任务的区别。

1.3 先把功能边界拆出来

不要再纠结“这个系统到底还缺什么功能”,先画清边界。

我的建议是拆成6个模块:

模块功能点说明
用户管理注册、登录、角色区分患者、医生、管理员三种角色
医生管理科室、职称、排班、擅长领域后台可维护,前端展示
预约与问诊在线预约、文字问诊、上传图片核心业务流
病历处方病历记录、处方开药、查看历史外键关系复杂,重点设计
消息通知预约成功、新问诊提醒、医生回复WebSocket实时推送
数据看板访问量、热门科室、高峰时段、医生负载大数据分析结果展示

这种边界划分会直接指导后面的数据表数量。业务不臃肿,才能写得完。很多同学的误区是一上来就加“在线支付、视频问诊、AI辅助诊断”,这些功能一旦接第三方SaaS或者训练模型,就会占用大量时间,最后连基础流程都没跑顺。

毕设项目评判标准不是功能越多越好,而是链路完整、逻辑清晰、能自圆其说。

2. Django 项目骨架与 ORM 实操

2.1 从“django创建app”到第一张业务表

创建项目的标准流程并不复杂,但很多人卡在第一步:把代码写进错误的位置。

我是这么做的:

python -m venv venv source venv/bin/activate # Windows环境用 venv\Scripts\activate pip install django channels channels-redis daphne django-admin startproject medical_platform cd medical_platform python manage.py startapp users python manage.py startapp doctor python manage.py startapp consult python manage.py startapp analysis

这里的前提是项目名叫medical_platform,下面拆了四个app。你要注意,app的名字一定别用太通用的模块名,比如test、util,容易和第三方库冲突,迁移时也容易乱。

“django创建app”看似是背命令,但背后有设计逻辑:每一个app负责一个领域。不要在users里写医生的全部逻辑,也不要把问诊记录塞进analysis模块。领域拆得清楚,后面维护成本会成倍下降。

每次建完app,记得在settings.py的INSTALLED_APPS里注册。这一步漏掉的话,数据表不会生成,很多新手第一次跑迁移没建表,多半就是漏了注册。

完成之后,先建第一张模型感受一下:

from django.db import models class Department(models.Model): name = models.CharField(max_length=100, verbose_name="科室名称") description = models.TextField(blank=True, verbose_name="科室介绍") sort_order = models.IntegerField(default=0, verbose_name="排序") class Meta: db_table = "sys_department" verbose_name = "科室" ordering = ["sort_order", "id"] def __str__(self): return self.name

这个表很简单,但要注意两个细节:一是db_table显式指定表名,避免Django默认生成的“app名_类名”在不同环境里不一致;二是Meta里设定了ordering,这样后台列表页和API查询都默认有序,省掉很多手工排序。

2.2 模型关系设计:患者、医生、问诊记录与权限

在线问诊系统的数据表设计,核心是一个轴心业务表“问诊记录”,它连接所有参与者。

假设你有这些字段:

from django.db import models from django.contrib.auth.models import User class PatientProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="patient_profile") real_name = models.CharField(max_length=50) gender = models.CharField(max_length=10, choices=[("M", "男"), ("F", "女"), ("O", "其他")]) birth_date = models.DateField(null=True, blank=True) phone = models.CharField(max_length=20, blank=True) class DoctorProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="doctor_profile") department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True) title = models.CharField(max_length=50) specialty = models.TextField(blank=True) is_online = models.BooleanField(default=False) class ConsultationRecord(models.Model): patient = models.ForeignKey(PatientProfile, on_delete=models.CASCADE, related_name="records") doctor = models.ForeignKey(DoctorProfile, on_delete=models.PROTECT, related_name="records") status = models.CharField(max_length=20, choices=[ ("pending", "待接诊"), ("ongoing", "问诊中"), ("finished", "已结束"), ("canceled", "已取消") ], default="pending") chief_complaint = models.TextField(verbose_name="主诉") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)

这里故意用了三种不同的外键策略,值得单独讲:

  • PatientProfile关联User用了CASCADE,意思是用户被删除,患者资料跟着删。这个逻辑符合账号注销场景。
  • DoctorProfile关联Department用了SET_NULL,科室被删除时医生不删除,只是科室置空。这样科室调整不会影响医生。
  • ConsultationRecord关联医生用了PROTECT,医生有关联问诊记录时禁止删除。这能保护医疗数据完整性,不会因为删一个医生实体把问诊记录全带走。

系统中还应该有“角色权限”。Django的auth自带User和Group,但问诊系统用通用很多。最简单的角色划分方式是:在Profile表中加role字段,或者在Django中给用户设分组。复杂一点的做法是把RBAC做出来,包括用户-角色-权限三级模型,后台里给不同角色分配菜单和操作权限。

毕设里呈现到RBAC这种程度,答辩老师会觉得你对权限理解到位了。实现也不难:

from django.contrib.auth.models import Group, Permission from django.contrib.auth.decorators import login_required, user_passes_test def is_doctor(user): return user.groups.filter(name="医生").exists()

在视图上加装饰器,就能实现“患者只能访问自己的问诊记录”“医生只能访问分配给自己的患者问诊单”这样的控制。

2.3 django执行查询-删除对象:最容易被忽略的三个坑

搜关键词的时候,“django执行查询-删除对象”这个短语频繁出现,说明很多人就是在这里踩了坑。

第一个坑是QuerySet的“惰性求值”。ORM的查询集并不会在定义时立刻访问数据库,而是在迭代、取值或调用print之前,它都是一个“待执行”状态。

records = ConsultationRecord.objects.filter(status="pending") # 到这里还没有查库 # 一旦执行 list(records) 或者 first() 才会有SQL执行

这个特性本身不是坏事,但新手容易在多次调用.count()和.filter()时忘了Django会重新触发SQL,导致性能看起来不稳定。解决方式是把需要复用的结果查询集直接转成list缓存,或者搞清楚自己只需要哪一条、哪一个范围。

第二个坑是删除对象的级联问题。很多人看到删除成功,没想到病历也被默认带走了。

patient = PatientProfile.objects.get(id=1) patient.delete() # 如果这个患者还有问诊记录,记录也会被CASCADE删掉

如果是真实业务,绝对不应该这么做。问诊记录属于医疗数据,通常要保存几年以上。正确做法是“软删除”:在模型里加一个is_active字段或is_deleted字段,删除时只改状态,不真正移除数据。

class PatientProfile(models.Model): is_active = models.BooleanField(default=True) def soft_delete(self): self.is_active = False self.save(update_fields=["is_active"])

第三个坑是批量删除时没有条件保护。比如你想清理三个月前的测试数据,写成了ConsultationRecord.objects.all().delete(),直接把线上数据全清掉。每个项目中,批量删除都必须先打印出受影响数量,再用事务包裹。

from django.db import transaction with transaction.atomic(): qs = ConsultationRecord.objects.filter(created_at__lt="2025-01-01") print("将会删除", qs.count(), "条") qs.delete()

事务的好处是万一删错了还能回滚。这种代码写进项目里,比“删库跑路”的教育意义强太多。

3. 实时推送模块实现:后台有数据,前端立刻更新

3.1 医院场景里为什么非要上 WebSocket

问诊系统的业务天然适合实时推送:医生登录后台,患者刚提交问诊申请,页面要是需要反复手动刷新才知道,体验会很糟糕。同样,患者在看诊过程中,医生回复了消息,前端也需要立刻弹出提示。

常规轮询方案是前端每隔几秒钟发起一次HTTP请求去拉数据。这个方法能跑,但会造成大量无效请求,尤其在问诊高峰期,几十个用户同时轮询,数据库压力不小。WebSocket的优势在于建立一次长连接,后台有数据就主动推送,前端不需要反复问。

正则表达式的比喻是“打电话”和“翻朋友圈”的区别。HTTP轮询像你反复去朋友圈刷新看别人有没有更新,WebSocket像对方主动给你打电话通知。

在项目里用Django实现WebSocket,最稳定的配套是channels。它给Django带来了异步处理能力,让Django可以在长连接场景下工作。

3.2 Channels + Redis 实现消息推送的完整链路

完整链路分为四层:配置文件、ASGI路由、消息消费者、前台浏览器收消息。

第一步,在settings.py里注册channels,并配置Redis作为channel layer:

INSTALLED_APPS = [ ... "daphne", "channels", ] ASGI_APPLICATION = "medical_platform.asgi.application" CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [("127.0.0.1", 6379)], }, }, }

注意INSTALLED_APPS里要有daphne,否则Django默认用自带ASGI服务器,兼容性会差一些。

第二步,修改asgi.py:

import os from django.core.asgi import get_asgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "medical_platform.settings") from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from django.urls import path from consult.consumers import ConsultationConsumer django_asgi_app = get_asgi_application() application = ProtocolTypeRouter({ "http": django_asgi_app, "websocket": AuthMiddlewareStack( URLRouter([ path("ws/consult/<int:record_id>/", ConsultationConsumer.as_asgi()), ]) ), })

第三步,写consumers.py:

import json from channels.generic.websocket import AsyncWebsocketConsumer class ConsultationConsumer(AsyncWebsocketConsumer): async def connect(self): self.record_id = self.scope["url_route"]["kwargs"]["record_id"] self.group_name = f"consult_{self.record_id}" await self.channel_layer.group_add(self.group_name, self.channel_name) await self.accept() await self.channel_layer.group_send( self.group_name, {"type": "notify.message", "message": "已进入问诊会话"} ) async def disconnect(self, close_code): await self.channel_layer.group_discard(self.group_name, self.channel_name) async def notify_message(self, event): await self.send(text_data=json.dumps({ "message": event["message"], "sender": event.get("sender", "system"), }, ensure_ascii=False))

这段代码做了三件事:用户连接时加入名为consult_记录ID的消息组;断开时退出;收到群消息时推给当前浏览器。

第四步,后台某个视图或Celery任务处理完数据后,调用channel_layer推送:

from channels.layers import get_channel_layer from asgiref.sync import async_to_sync channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( "consult_5", { "type": "notify.message", "message": "医生已经接收您的问诊,请查看回复", "sender": "doctor", } )

这样护士或系统在后台改一条记录、转诊一个患者,浏览器立即能弹通知。标题里那句“后台有数据,前端推送”,代码上就是这么闭环的。

3.3 网关层与部署阶段的常见翻车点

本地跑的时候,你必须用daphne而不是runserver才能完整处理WebSocket:

daphne -b 0.0.0.0 -p 8000 medical_platform.asgi:application

如果测试时发现WebSocket一直连接不上,先检查三件事:

  • Redis进程是否启动,用redis-cli ping验证连通性。
  • 浏览器控制台请求地址是否写成了ws://而不是wss://。
  • 连接路径是否和asgi.py里配置的路由一致,多一个斜杠都不行。

生产部署时还会遇到超时和跨域问题。如果你的项目用了Nginx反向代理,300秒超时对WebSocket来说是一个不小的障碍。一定要单独给/ws/路径设置更长的超时时间,或者在Nginx配置里允许Upgrade。另外,如果前端和后端分离,注意跨域,connect阶段被浏览器拦截,页面日志不会报明显错误。

部署阶段不用追求高可用,但Redis重启策略、日志输出、异常重连机制要能讲出来。答辩问到“断网怎么办”,你说“客户端监听onclose,并做重连”就比“不知道”强很多。

4. 大数据技术在问诊系统里的落地路径

4.1 采集层:埋点、日志与用户行为表

大数据分析的第一步不是写算法,而是先把数据采集上来。很多毕设在这块是空的,评委问“数据怎么来的”,只能说“手动造的”。手动造不是不行,但你要造得合理,还要有采集逻辑支撑。

我建议在项目里增加一个用户行为埋点。最简单的方案是写一个中间件:

import time from django.utils import timezone class BehaviorLogMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): start = time.time() response = self.get_response(request) duration = int((time.time() - start) * 1000) if request.user.is_authenticated: from analysis.models import UserBehaviorLog UserBehaviorLog.objects.create( user=request.user, path=request.path, method=request.method, duration_ms=duration, created_at=timezone.now(), ) return response

这样一个中间件能把每次请求的路径、耗时、访问时间都记录下来。数据量不大,但足够支撑“访问趋势”“最热页面”等分析。

更进一步,可以在搜索症状、查看医生主页、提交问诊申请这些关键动作里手动插入行为记录:

# 视图里 UserBehaviorLog.objects.create( user=request.user, path=request.path, action="search:doctor", detail=keyword, )

给行为记录加action字段,可以区分页面浏览和按钮触发。这样数据采集层就不再是空话。

4.2 分析层:Pandas 快速分析,Spark 讲得清原理

有了行为表,分析层就开始变得有意义。我常用Pandas先把明细数据统计出结果,再用Spark做一轮更大体量的模拟数据分析,保证答辩时有“离线分析”的环节。

Pandas能做的分析:

import pandas as pd df = pd.read_csv("behavior_logs.csv", parse_dates=["created_at"]) df["hour"] = df["created_at"].dt.hour hour_group = df.groupby("hour").size().reset_index(name="count") print("访问高峰时段:", hour_group.sort_values("count", ascending=False).head(3))

Spark版本的逻辑类似,但数据处理量更大,加了一个分布式计算的仪式感:

from pyspark.sql import SparkSession from pyspark.sql.functions import hour, count spark = SparkSession.builder.appName("consultation-analysis").getOrCreate() df = spark.read.csv("behavior_logs.csv", header=True, inferSchema=True) df.withColumn("hour", hour(df.created_at)) \ .groupBy("hour").count() \ .orderBy("count", ascending=False) \ .show(5)

这个阶段的参数选择可以讲得很细:比如为什么用窗口函数统计医生负载,为什么要在非高峰时间跑批量任务。问诊系统里,分析任务不需要实时响应,凌晨用Spark跑一次前一天的全量数据,写入汇总表,白天的大屏和报表直接读取汇总结果。这是典型的Lambda架构简化版:事务数据走业务库,分析数据走离线批处理。

4.3 展示层:把分析结果变成答辩能看的可视化

光有数据表没有图表,无法直观给评委传达“我做了大数据分析”。展示层选用ECharts比较合适,它有Django模板可以直接嵌入的版本。

我做过一个简单的数据大屏,包含四个核心指标:

  • 今日问诊量折线图,横轴小时,纵轴订单数。
  • 热门科室Top5横向柱状图。
  • 医生负载排行表。
  • 患者地域来源分布饼图。

后端只需提供一个API让前端拿汇总数据:

from django.http import JsonResponse from analysis.models import DoctorLoadStat, HourlyConsultStat def dashboard_data(request): hour_data = list(HourlyConsultStat.objects.order_by("hour").values_list("hour", "consult_count")) top_doctors = list(DoctorLoadStat.objects.order_by("-consult_count")[:5].values("doctor_name", "consult_count")) return JsonResponse({"hour": hour_data, "top_doctors": top_doctors})

前端用ECharts在页面里把这些数据渲染出来。答辩时这套流程就叫“数据链路闭环”:埋点采集、离线分析、结果存储、前端展示。数据量也许不算大,但分析思维已经体现了。

5. 源码救场:怎么把“免费项目”改成自己的作品

5.1 拿到源码先做三件套检查

先做三件套检查。第一看项目结构和依赖,是否有requirements.txt,是否用了虚拟环境;第二看数据库迁移文件,是否有完整的migrations;第三看README,是否写了启动步骤。缺任何一样,都要提高警惕。

免费的Django毕设源码千篇一律,你花一小时下载,可能还要花两天填坑。下面几个信号直接决定它的质量:

检查点好源码的标志烂源码的翻车现场
requirements.txt版本号清晰只有django,没有版本
migrations目录每张表都有迁移文件完全没有,跑完迁移后模型对不上
静态文件路径清晰图片和CSS硬编码到C盘
配置文件settings用os.environ读取把数据库密码写死在代码里
文档有启动步骤只有一个空README或广告
代码注释关键逻辑有解释代码缩写混乱,没有注释
数据库有迁移或SQL备份数据库文件有误或打不开

如果是你从网上下载的“万套教程打包送”,不要迷信压缩包的大小。先解压看代码,很多打包资源是几十个项目塞在一起,复用意义不大,能挑出一个可改造的骨架就是胜利。

5.2 我处理过的翻车现场和对应修法

翻车现场一:依赖冲突。旧项目用Django 2.2,你机器上是Python 3.11,一启动就报ImportError: cannot import name 'force_text' from 'django.utils.encoding'。解决方案不是硬降Python版本,而是先更新到Django 3.2或4.2兼容分支,再把force_text改成force_str。绝大部分老项目升级迁移只需要改那几个废弃API。

翻车现场二:数据库连接错误。源码默认配置是MySQL,但你连不上远程库。别直接改settings,先把数据库改成SQLite跑通本地:

DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", } }

本地跑通后,再考虑要不要上MySQL。很多同学一上来就踩MySQL认证插件版本问题,浪费大量时间。毕设优先跑通,再谈部署。

翻车现场三:静态文件全部404。模板能打开但没有样式,多半是STATIC_URL配置和静态目录不一致。打开settings检查:

STATIC_URL = "/static/" STATICFILES_DIRS = [BASE_DIR / "static"]

模板里也要正确加载:

{% load static %} <link rel="stylesheet" href="{% static 'css/base.css' %}">

如果还不行,用python manage.py collectstatic把静态文件收集到指定目录,再迁移部署流程。

5.3 顺手给后台换皮肤:Django Unfold 与 RBAC 权限

如果你拿到的源码默认后台长着Django自带的面孔,想提升观感,用Django Unfold是一个性价比很高的方案。它能快速把admin装饰成现代化卡片式界面,不需要改太多业务代码。

pip install django-unfold

安装后在INSTALLED_APPS顶部加入unfold,并继承Unfold的ModelAdmin:

from django.contrib import admin from unfold.admin import ModelAdmin from consult.models import ConsultationRecord @admin.register(ConsultationRecord) class ConsultationRecordAdmin(ModelAdmin): list_display = ["id", "patient", "doctor", "status", "created_at"] list_filter = ["status", "created_at"]

页面会立刻从“管理后台”变成“运营平台”的观感。这个加分项不用动业务逻辑,成本极低。

RBAC权限也可以在后台配合使用:创建“医生组”“患者组”“管理员组”,把模型的操作权限细分到不同角色。Django的Group和Permission本身就支持这个,你只需要在admin里创建并分配。

6. 实战问题排查与答辩避坑

6.1 高频故障排查速查表

长期做Django项目的人会怀念那些“跑一下就知道”的报错,但新手总是卡在同样几个地方。整理了一份高频故障表:

故障现象可能原因排查方法
迁移后表结构不对忘记注册appINSTALLED_APPS检查
页面样式全无静态文件路径错误STATIC_URL与模板加载标签
登录后没权限未分配组或session问题检查数据库session表
多个对象同时更新异常并发覆盖用select_for_update()锁行
Redis连接失败Redis未启动或密码错误redis-cli ping
WebSocket连不上asgi路由、端口或代理配置错误控制台看握手状态
查询特别慢缺少索引或没用select_related看SQL日志
批量删除误操作没有事务保护先统计count再删
后台管理样式旧默认Django admin换Django Unfold

实操心得:遇到问题不要急着改代码,先看控制台完整报错,尤其在Django项目里,日志和反向链路往往能直接定位整个问题的最关键上下文。

6.2 答辩现场常被追问的五道题

第一道:“你这个大数据分析用到哪些技术?”回答模板:采集层用了Django中间件和日志记录,分析层用了Pandas做数据清洗和聚合,同时用Spark模拟离线分析场景,结果写入汇总表供给可视化。重点强调“理解数据从哪来、清洗逻辑是什么、分析结果如何使用”。

第二道:“如果数据量增加到千万级,现在的方案能支撑吗?”不要硬说“能”。正确回答是:当前方案满足课程设计数据量级;如果要支撑千万级,会引入分区表、索引优化、消息队列异步写入、Spark集群化。评委会觉得你有扩展思维。

第三道:“WebSocket和HTTP请求的区别是什么?”对照HTTP短连接的特点,先说明轮询浪费资源,再说明WebSocket建立长连接、服务端主动推送,给出完整实现路径。

第四道:“删除一个患者,问诊记录会怎么样?”你说出CASCADE、PROTECT、SET_NULL三种策略的区别,并指出医疗记录应该避免物理删除。这道题是隐藏的送分题。

第五道:“你如何验证项目的可靠性?”可以提事务保护、软删除、日志审计、权限控制。如果再把代码里用过的select_for_update()、事务回滚逻辑讲出来,比背十页理论都有效。

6.3 用好数据表审计,让毕设项目“有灵魂”

毕设项目想从“工具”升级成“系统”,要害之一是审计。在线问诊涉及医患数据,操作留痕是必须的。

我在项目里加了三张审计表:

  • 登录日志表:记录登录时间、IP、User-Agent。
  • 操作审计表:记录谁在什么时间创建、更新、删除了哪条记录。
  • 问诊流转表:记录从待接诊到结束的每一个状态变更。

状态流转表设计大概是:

class ConsultationFlow(models.Model): record = models.ForeignKey(ConsultationRecord, on_delete=models.CASCADE) from_status = models.CharField(max_length=20) to_status = models.CharField(max_length=20) operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) remark = models.CharField(max_length=200, blank=True) created_at = models.DateTimeField(auto_now_add=True)

每次问诊状态改变,就插入一条流转记录。这样答辩时,你可以现场演示一条记录从“待接诊”变为“问诊中”,后台审计表立刻多一条历史记录。评委看完之后,会对你的项目产生“能落地”的判断。

最后再分享一个经验:答辩前一夜,不要急着背稿子,而是把项目从零启动一遍,注册两个账号,扮演医生和患者,跑通一次完整的问诊流程。很多项目表面上有一堆功能,演示时却在最基础的登录环节翻车。你亲手把这条链路走通一遍,比任何花哨的新技术都更让人踏实。真到了现场,你就知道一个跑得顺的主流程,才是毕业设计最扎实的底气。

返回列表