资讯详情

资讯详情

基于Python的药品管理系统毕设:模块设计、数据库与答辩全流程解析

基于Python的药品管理系统毕设源码从选题到答辩全流程解析毕业设计的选题十个里有八个绕不开管理信息系统而药品管理系统又是计算机专业和软件工程专业里出镜率最高的那几个方向之一。原因不复杂这类系统业务边界清晰、需求可量化、数据库设计有讲究既能体现课程知识又不会夸张到做不完。这篇内容就专门拆解一个基于Python的药品管理系统从模块设计、数据库建模、代码落地到论文答辩事无巨细理一遍给正在准备毕设的同学一套可以直接上手的参考路线。先看系统定位。药品管理系统解决的是一组非常具体的业务问题药品信息太多人工登记容易错库存盘点靠手写表格效率太低效期管理做不到位过期药品没法及时发现进销存记录分散统计报表要花半天时间。系统把这套流程搬上Web端让管理员、药房人员、普通员工在浏览器里就能完成日常操作数据集中存储权限分级控制报表自动生成。这就是最常见的毕设定位工作量适中功能完整度可控技术栈有发挥空间论文也有充足的叙述空间。对做毕设的同学来说这套系统还有一个额外的好处药品领域的业务逻辑相对标准化网上可参考的现成管理方案很多需求调研写起来不费劲答辩评委也不会对业务规则提出难解释的质疑。作为毕设项目它是一个安全稳定且上限不低的选题。1. 业务模块拆解一个药品管理系统到底需要做什么很多同学拿到题目之后的第一反应是直接打开IDE写代码这是最常见的错误。正确顺序是先做业务建模把系统要干什么、为谁服务、有哪些输入输出彻底搞明白后面写代码才有方向。药品管理系统站在业务角度核心就是人货场三件事人有谁、货怎么管、操作发生在线上的什么地方。1.1 核心业务闭环采购、入库、销售、盘点药品管理系统的业务主链路本质上是一个库存流转闭环。采购环节是链路起点。采购员根据库存下限和销售趋势生成采购计划药房负责人审批后向供应商下单药品到货后执行入库操作系统自动更新库存数量并生成采购入库单。入库单的字段设计要注意药品名称、规格、生产厂家、生产批号、生产日期、有效期至、采购数量、采购单价、入库时间、操作人这些字段少任何一个后面做效期提醒和成本核算都会缺素材。销售环节是链路的中间节点。收银员在系统里选择药品、录入数量系统自动计算金额并扣减库存。这里有一个很关键的业务问题销售时到底用不用处方审核流程毕设里一般做两种方式一种是纯零售型选药、结账、出小票逻辑简单另一种是医院药房型需要录入患者信息、医生开方信息甚至对接处方单号。建议做简单版时也要预留一个处方单号字段答辩时能多一个可讲的场景。盘点环节是链路的校验点。库存账面上的数字和实物数量不可能永远一致搬运损耗、录入错误、过期下架都会造成账实差异。盘点功能要做的是录入实测数量、系统自动计算盈亏数量、生成盘点差异单。这个功能看着不起眼却是论文里系统创新点部分的好素材因为纯增删改查的系统基本不会做盘点闭环。1.2 用户角色与权限边界药品管理系统最少要有三种角色。管理员是超级用户拥有全部模块的访问权包括用户管理、权限分配、系统参数设置、数据备份。药房操作员负责日常药品出入库操作、库存查询与盘点录入。收银员或销售员只能访问销售收银界面、销售记录查询不能接触采购价格和库存修改类操作。权限设计在毕设阶段不需要上RBAC那套完整的权限框架用一张用户表加一个角色字段再在请求层做角色判断就足够。但如果你想让项目更有亮点可以引入角色-菜单权限的映射表设计菜单表存系统所有可访问的功能节点角色表定义角色名称角色-菜单关联表定义每个角色能看哪些功能。前端渲染菜单时按当前用户角色过滤后端接口再校验一次角色权限双保险。1.3 药品信息的字段建模细节药品信息表的字段设计直接决定系统能支撑到多细的业务场景。最基本的字段包括药品编码、通用名、商品名、剂型、规格、单位、生产厂家、批准文号、存储条件、售价、进货价、库存数量、库存下限、有效期至等。这里有两个容易被忽略的点。第一个是药品编码不要用自增主键直接当药品编码建议采用类别前缀序号的复合编码规则比如YP-10001。原因很实际药品编码是要打印到标签上、录入到其他系统里的有业务含义的编码比纯数字主键可读性强得多而且答辩时能讲出一套编码规则本身就是加分项。第二个是存储条件字段很多药品需要阴凉、冷藏、避光保存界面端可以做成下拉枚举但数据库里建议直接存字符串避免因为枚举扩展而频繁调整表结构。2. 技术选型为什么Python这套组合最适合毕设管理系统的技术栈选择范围很大Java的Spring Boot、PHP的Laravel、Node.js的Express都能做。但基于Python的方案在这个题目上有一个天然优势Python语法简洁后端逻辑写起来速度快对不擅长大型框架的同学尤其友好。作为一个毕设效率就是性价比谁能用最短时间跑通完整闭环谁就有更多时间打磨论文和答辩PPT。2.1 Web框架选型Django还是Flask药品管理系统这种标准业务型项目我建议优先选择Django。原因在于Django开箱即用的内置功能覆盖面太全了。Admin后台直接在Django自带admin模块上改造CRUD功能免费送ORM自动建表、自动迁移数据库变更不用手写SQL内置用户认证体系登录、会话、密码哈希全套都有。这意味着你只需要关注业务代码本身框架层面的基础设施完全不用重复造轮子。Flask的优势是轻量灵活但你需要自己组装ORM、表单验证、登录插件、数据库迁移工具组装成本大约多花3到5天时间。对时间紧、只想尽快跑通系统的毕设场景这一周的时间成本已经足够改变整个项目的完成度。当然如果你本身对Flask非常熟悉或者论文侧重研究轻量级框架在信息管理系统中的应用那Flask也是好选择。关键判断依据是你最熟悉哪种框架就用哪种不要为了炫技而冒险。2.2 数据库选型SQLite起步、MySQL收尾数据库选择建议分阶段切换。开发阶段直接用SQLite零配置、单文件、不需要安装数据库服务IDE一跑就能开始写代码。但毕设最终展示阶段一定要切换到MySQL原因一方面是答辩老师默认管理系统就该用主流数据库另一方面是MySQL在并发稳定性、数据容量、管理工具生态上确实更扎实。切换到MySQL的实质操作只有两步。第一步在settings配置里把数据库引擎改为django.db.backends.mysql同时填写HOST、PORT、USER、PASSWORD、NAME参数。第二步用python manage.py migrate将模型同步到MySQL再把原有数据导出导入。注意Windows环境下需要装mysqlclient或pymysql驱动Django使用的版本不同驱动兼容性也有差异建议提前查官方文档做对应处理。2.3 前端方案不要在前端上花太多时间医药系统的目标用户是药房工作人员不是消费者界面好用比花哨重要。前端部分用Django模板语法加Bootstrap就完全够用表格展示用Bootstrap Table表单验证用基础JavaScript图表部分引入ECharts直接渲染库存趋势图和销售统计图。千万不要在这个阶段引入前后端分离。Vue加Django REST Framework的组合虽然好看但开发量会成倍增加联调成本、跨域问题、权限同步都会消耗大量时间而这些复杂度对毕设而言并不产生对等的收益。前后端分离的架构讲起来好听实际落到6月底要交论文这个时间节点上很多同学会非常被动。3. 数据库设计药品库存系统的表结构如何组织数据库设计是整个项目中影响最深远的环节。表结构设计得好后面写业务代码基本是水到渠成设计得乱每写一个功能都要回头改表改表又要动数据越改越难受。药品管理系统的表设计围绕进销存用户权限展开核心表不超过十张。3.1 核心数据表的设计方案先列一张完整的核心表清单表名主要字段作用说明auth_user继承Django默认用户表存储登录账号、密码、角色标识role角色ID、角色名称定义管理员、药房、收银员等角色user_role用户ID、角色ID多对多关联用户可多角色medicine_category类别ID、类别名称、父类别ID药品分类支持二级分类medicine_info药品基础信息见上文字段药品主表全系统最核心的表supplier供应商编号、名称、联系人、电话采购环节的供应商档案purchase_order采购单号、供应商ID、采购日期、总金额、状态采购单主表purchase_order_item采购单ID、药品ID、数量、单价采购单明细一单多品stock_batch批次号、药品ID、生产批号、有效期、入库数量、剩余数量批次库存表支持效期管理sale_order销售单号、收银员ID、销售时间、总金额销售主表sale_order_item销售单ID、药品ID、数量、单价、小计销售明细表stock_check盘点单号、盘点时间、盘点人、状态盘点主表stock_check_item盘点单ID、药品ID、账面数量、实盘数量、盈亏数量盘点明细这套表结构覆盖了业务闭环的所有关键节点而且满足第三范式的基本要求主表只存基础信息和汇总数据明细数据全部下沉到子表通过外键关联。第三范式在这里不是理论要求而是实际需求——一张销售单需要记录20种药品如果全部塞在一条记录里扩展性和统计性能都会出问题。3.2 批次库存与效期管理的数据逻辑药品库存和图书库存最大的区别在于批次管理。同一款药品进货两个月前的那一批和昨天新到的那一批有效期完全不同。业务上必须能够追溯到每批药品的生产批号和有效期这也是药监管理上的基本要求。在设计上药品表存储的是静态信息批次库存表存储的是动态数量。每次采购入库时创建一条新的批次记录录入生产批号、生产日期、有效期至和入库数量。销售扣减库存的时候系统需要按照先进先出、近效期先出的规则自动定位到对应的批次记录上进行扣减。近效期预警功能就建立在批次表之上定时任务每天检查各批次的有效期至字段如果距离当天天数小于设定的阈值比如90天系统就标记为预警批次在首页或库存列表中突出显示。这个逻辑在Django中写起来并不复杂查出来有效期小于阈值日期的批次列表前端渲染时加上预警样式就行。3.3 ORM模型设计示例用Django ORM定义核心模型时代码组织需要有清晰边界。以药品表为例模型代码如下from django.db import models class MedicineCategory(models.Model): name models.CharField(max_length50, verbose_name类别名称) parent models.ForeignKey(self, nullTrue, blankTrue, on_deletemodels.CASCADE, verbose_name父类别) class Meta: db_table medicine_category verbose_name 药品类别 def __str__(self): return self.name class MedicineInfo(models.Model): medicine_code models.CharField(max_length20, uniqueTrue, verbose_name药品编码) generic_name models.CharField(max_length100, verbose_name通用名) trade_name models.CharField(max_length100, verbose_name商品名) category models.ForeignKey(MedicineCategory, on_deletemodels.PROTECT, verbose_name药品类别) dosage_form models.CharField(max_length50, verbose_name剂型) # 片剂、胶囊、注射剂等 specification models.CharField(max_length50, verbose_name规格) unit models.CharField(max_length10, verbose_name单位) manufacturer models.CharField(max_length100, verbose_name生产厂家) approval_number models.CharField(max_length50, verbose_name批准文号) purchase_price models.DecimalField(max_digits10, decimal_places2, verbose_name进货价格) sale_price models.DecimalField(max_digits10, decimal_places2, verbose_name销售价格) stock_lower_limit models.IntegerField(default0, verbose_name库存下限) storage_condition models.CharField(max_length100, verbose_name存储条件) status models.BooleanField(defaultTrue, verbose_name是否启用) create_time models.DateTimeField(auto_now_addTrue, verbose_name创建时间) class Meta: db_table medicine_info verbose_name 药品信息 def __str__(self): return f{self.generic_name} {self.specification}这里有几个建模时的注意点。第一医药领域药品信息中批准文号字段要加unique约束同一个批准文号通常对应一个具体规格的药品重复录入会被数据库拦截。第二药品类别用自关联外键实现无限级分类虽然毕设中实际只用两级但这个设计保留了扩展空间。第三价格字段用DecimalField而不是FloatField浮点类型在涉及金额计算时会产生精度问题这是所有财务相关系统的共识。库存扣减逻辑推荐放到事务里执行防止并发条件下超卖from django.db import transaction transaction.atomic def deduct_stock(medicine_id, quantity): batches StockBatch.objects.filter( medicine_idmedicine_id, remaining_quantity__gt0 ).order_by(expiry_date) to_deduct quantity for batch in batches: if to_deduct 0: break deduct_qty min(batch.remaining_quantity, to_deduct) batch.remaining_quantity - deduct_qty batch.save() to_deduct - deduct_qty用order_by(expiry_date)排序即可实现近效期优先出库按有效期从早到晚逐批次扣减库存。4. 核心功能实现从库存预警到销售流水系统搭建起来之后工作量集中在几个核心功能点。真正体现一个毕设完成度的往往不是CRUD页面写了多少而是关键业务场景有没有闭环异常情况有没有处理。4.1 库存预警流程的实现要点库存预警包含两个维度数量下限预警和近效期预警。数量下限预警的逻辑很简单遍历药品表找出当前库存总量小于库存下限的药品。这里需要一条聚合查询from django.db.models import Sum, F low_stock_medicines MedicineInfo.objects.annotate( total_stockSum(stock_batch__remaining_quantity) ).filter( total_stock__ltF(stock_lower_limit) )这段查询用annotate把每个药品的批次余量求和再和库存下限字段直接比较。注意Sum需要传关联关系的路径这里stock_batch是MedicineInfo的反向关联名ORM会自动生成联合查询。近效期预警则需要在视图函数里动态计算from datetime import date, timedelta def get_soon_expiring_medicines(days90): threshold_date date.today() timedelta(daysdays) return StockBatch.objects.filter( remaining_quantity__gt0, expiry_date__ltethreshold_date ).select_related(medicine)再强调一次预警功能不要做成每次打开页面都要跑的常规查询更适合的做法是登录成功后调用一次将结果存入内存缓存比如Django的cache框架或者直接放session减少数据库压力。4.2 销售收银事务与单据生成销售收银是药品管理系统操作频率最高的功能对事务一致性的要求也最高。一次销售动作涉及销售单主表新增、销售明细表批量新增、库存批次表批量扣减三个写操作任何一个失败都会导致数据不一致。完整的收银接口逻辑应该这样组织transaction.atomic def create_sale_order(request): cart_items json.loads(request.POST.get(cart_items)) total_amount 0 sale_order SaleOrder.objects.create( operatorrequest.user, total_amount0, pay_typerequest.POST.get(pay_type, cash) ) for item in cart_items: medicine MedicineInfo.objects.select_for_update().get(iditem[medicine_id]) subtotal medicine.sale_price * item[quantity] SaleOrderItem.objects.create( ordersale_order, medicinemedicine, quantityitem[quantity], pricemedicine.sale_price, subtotalsubtotal ) deduct_stock(medicine.id, item[quantity]) total_amount subtotal sale_order.total_amount total_amount sale_order.save() return sale_order这段代码里有几个很关键的细节。第一是select_for_update()这个方法是悲观锁它会锁定对应行直到事务提交防止两个收银员同事销售同一药品时出现超卖。第二是销售小票的生成建议直接渲染一个HTML模板再用浏览器的打印功能输出比引入复杂报表引擎简单得多。第三是金额计算全部走Decimal单价是DecimalField读取的Decimal对象数量是整数乘出来的结果天然是Decimal不会踩浮点坑。4.3 数据统计与可视化折线图、柱状图、占比图一个只有增删改查的药品管理系统在答辩时很容易被评价为工作量偏少。统计模块是提升项目视觉量和内容深度的关键部分。统计维度至少做四个。药品销售排行按销量排序取前20名用柱状图展示月度销售趋势按自然月聚合销售额用折线图展示药品类别占比按类别聚合销售金额用饼图展示库存预警统计展示各预警类型的药品数量用仪表盘或卡片数展示。ECharts的引入方式非常简单在模板中加载echarts的CDN链接写一个div容器再用JavaScript填充数据div idtrendChart stylewidth: 100%; height: 400px;/div script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script script var chart echarts.init(document.getElementById(trendChart)); var dates {{ dates|safe }}; var amounts {{ amounts|safe }}; chart.setOption({ tooltip: {}, xAxis: { type: category, data: dates }, yAxis: { type: value }, series: [{ type: line, data: amounts }] }); /script后端视图函数只需要把统计数据整理成列表通过json_script模板标签传递到前端即可。Django模板变量默认会转义特殊字符对于JSON数据必须用|safe过滤器或者json_script标签否则渲染会出问题。5. 源码组织与关键细节毕设代码怎么写得像样许多同学毕设代码写得飞快但架不住导师一打开项目就摇头。问题往往不出在功能上而在于项目组织乱、命名不规范、关键逻辑没有注释、异常处理太少。源码整体的观感某种程度上比功能是否多一个按钮还重要。5.1 项目目录结构规范一个结构合格的Django项目目录划分应该一眼就能看懂。推荐按Django官方应用划分方式组织medicine_system/ ├── manage.py ├── requirements.txt ├── README.md ├── config/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── apps/ │ ├── users/ │ │ ├── models.py │ │ ├── views.py │ │ ├── urls.py │ │ └── forms.py │ ├── medicines/ │ │ ├── models.py │ │ ├── views.py │ │ └── urls.py │ ├── purchase/ │ │ └── ... │ ├── sale/ │ │ └── ... │ └── reports/ │ └── ... ├── templates/ │ ├── base.html │ ├── users/ │ ├── medicines/ │ ├── purchase/ │ ├── sale/ │ └── reports/ ├── static/ │ ├── css/ │ ├── js/ │ └── images/ └── media/注意这里把每个业务模块拆成独立的Django app而不是把所有models放在一个文件里。apps目录是业务承载体config目录是全局配置templates和static目录是前端资源。这种结构对答辩时讲解代码非常有利说到哪一部分功能就能直接指到对应的文件条理清晰。5.2 界面视觉与交互的逻辑药品管理系统的用户是药房工作人员他们每天操作系统的时间可能长达几个小时界面的可用性直接影响使用体验。配色上建议以深蓝色作为主色调白色为底色。医疗行业界面尽量避免大红大绿的糖果色深蓝传达专业感和可信度。布局上左侧固定导航栏展示系统模块列表右侧上方是用户信息和退出按钮中间内容区展示数据表格。这个布局几乎不需要额外设计直接套用一个开源的Admin模板比如AdminLTE开源版或基于Bootstrap的自制模板即可。交互细节上需要注意三点。表格操作列必须包含编辑、删除两个基础操作删除操作必须二次确认表单提交后要有成功提示数据校验不过要有明确的错误提示分页组件必须加上药品数量庞大时一个页面全部展示会导致页面卡顿Django内置的Paginator可以直接使用前端配合Bootstrap分页样式渲染。5.3 部署与演示环境答辩现场不出洋相毕设答辩翻车概率最高的场景是现场演示环节原因一半是代码本身有Bug另一半是环境问题。不管是本地笔记本演示还是服务器演示都要提前准备一个干净的可演示环境。推荐的做法是本地使用SQLite开发完毕后再切换MySQL答辩时使用一台配置好全套环境的机器数据库预置一份数据量适中的演示数据。医嘱数据量不宜太少也不宜过大100种药品、300条销售记录、20条采购单这个量级能让统计图表有内容展示又能保证系统响应速度不受影响。部署方式上最简单的方案是在本地运行python manage.py runserver 0.0.0.0:8000浏览器直接访问。如果导师要求线上访问可以用一台云服务器安装Nginx加Gunicorn部署Django项目MySQL放在本机。Nginx负责接收HTTP请求和托管静态文件Gunicorn是Python应用服务器跑Django应用本身。过程不复杂但环境配置步骤比较多不建议答辩前夜才开始折腾。6. 毕设论文和答辩的加分思路项目做完只是毕设的一半论文和答辩占比同等重要。常见的误区是论文写得像用户手册通篇都在描述点击某个按钮会出现什么页面没有学术性也没有设计思路的分析。6.1 论文结构怎么组织更有层次论文建议按六个章节展开。绪论部分聚焦研究背景和意义重点解释当前药品管理信息化不足、手工管理方式的缺陷结合国家药品管理法规对信息化追溯的要求引出系统开发的必要性。需求分析部分务必包含用例图、功能性需求表、非功能性需求表明确各角色在系统中的行为操作。系统设计部分重点是总体架构图、模块结构图、数据库ER图、核心表结构说明。系统实现部分按模块展示核心代码片段并配合核心界面截图每段代码旁边都要有设计说明文字。系统测试部分覆盖功能测试、性能测试、兼容性测试用标准测试用例格式描述。最后总结与展望简练地说明项目成果与不足。论文中最容易被导师看重的是数据库设计章节的系统性和测试章节的完整度。数据库ER图用Visio或draw.io画清楚标注主外键关系和一对多关系这部分是计算机专业毕业论文评阅的硬指标。6.2 答辩演示的节奏控制答辩演示时间通常限制在10到15分钟展示内容要有取舍。建议开场用2分钟介绍系统背景和功能列表中间8分钟演示核心业务流程——从登录到添加药品信息、创建采购单、完成入库、执行一笔销售、查看库存预警、最后打开统计报表形成完整业务线的演示路径。演示时要刻意展示不易出错的场景不要把常规按钮逐个点一遍。回答评委问题时注意引导思路比如被问到库存为什么会不准确时可以顺势讲盘点流程的设计思路被问到为什么选用MySQL时可以从数据一致性、并发表现、生态工具三个角度展开。提前把可能被问到的问题列一份清单逐一准备答案比临时发挥要稳得多。6.3 系统可以扩展的方向毕设交付之后如果还有时间精力或者导师希望往纵深打磨有两条比较有性价比的扩展路径。一种是增加药品过期自动预警的定时推送。引入APScheduler或Celery定时任务每天固定时间检查效期通过邮件或短信通知管理员低库存和近效期药品清单。这个功能在企业级系统里是标配在毕设中做到功能演示即可。另一种是引入数据可视化大屏模式。做一个独立的统计展示页面把今日销售额、销售额趋势、药品类别占比、出入库数量等指标用大屏风格布局展示。在答辩演示时全屏播放视觉冲击力非常强往往能直观改变评委的第一印象。实现方式依然是ECharts只是布局和样式换套思路开发周期两三天就能完成。7. 源码交付前的自检清单到了最终交付阶段有一份清单建议逐条过一遍避免细节翻车。功能层面检查登录验证是否支持错误次数限制密码是否用加密方式存储检查库存为负数的可能性是否存在扣减操作是否全部走事务检查修改药品信息时是否影响已有关联单据的完整性检查删除操作是否做了外键保护有引用关系的记录应当禁止物理删除。代码层面检查数据库密码和密钥等敏感信息是否写入代码文件应该放到环境变量或配置文件并加入版本忽略列表检查代码中有没有遗留的调试输出语句检查requirements.txt是否完整列出了所有依赖库及版本号检查README里有没有写清楚部署步骤、管理员账号初始化方式、数据库初始化脚本。数据层面检查测试数据中是否包含不规范的模拟信息药品名称和厂家名称如果要用虚拟数据要确保看起来真实且不会产生误解导出数据库脚本时确认编码为UTF-8避免中文乱码。文档层面检查论文里所有截图是否更新为最终版本数据库变更后ER图和表结构说明是否同步修改一致。源码和论文中出现的日期、数据、截图内容要保持完全对应这是评阅中最常被挑出的问题。系统本身不难真正拉大差距的是细节完成度。我见过不少功能平平但细节扎实的毕设拿到优秀评价也见过功能丰富但出错一堆、文档前言不搭后语的方案被反复要求修改。药品管理系统这个题目从业务理解到代码落地全程认真走一遍学到的东西一点不比大型项目少关键是别急着写代码先把逻辑想清楚代码自然而然地就顺了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →