最近接了个课程设计级别的项目,要把一个医药信息管理系统完整做出来,技术栈锁定 Python + Django,还要附带数据库脚本和说明文档。这类系统在高校课程设计和毕业设计里出现频率极高,很多同学卡在同一个地方:框架会用,但不知道怎么把业务逻辑和数据库设计得严谨;功能能跑,但经不起细节追问。这篇文章我把整个项目从设计到落地的完整思路掰开揉碎讲一遍,包括数据库怎么建模、Django 里怎么把增删改查写得干净、权限和日志怎么处理、以及最后怎么把系统跑起来。
无论你是刚学完 Django 基础、准备做课程设计的学生,还是在职想快速上手一个完整 Web 项目开发的开发者,这篇文章都能给你一套可以直接抄作业的方案。我会尽量模拟一个真实的开发过程,把踩过的坑、改进过的设计、以及源码里值得琢磨的细节都说清楚。
1. 系统整体设计与技术选型思路
1.1 为什么选 Python + Django 这套组合
市面上能做 Web 信息管理系统的方案其实不少,光是 Python 生态里就有 Flask、FastAPI,更别说 Java 的 Spring Boot、PHP 的 Laravel。但这个项目最后敲定 Django,我是从三个维度衡量的。
第一是开发效率。Django 自带 Admin 后台、ORM、表单处理、认证系统、安全防护,这些对一个信息管理系统来说是刚需。医药信息管理系统虽然有自定义的业务逻辑,但本质上还是围绕药品、供应商、库存、销售单据的增删改查,Django 的脚手架能在一小时内把项目骨架搭完,剩下的精力可以全部放在业务细节上。
第二是安全性。医药行业的数据敏感度高,Django 默认提供的 CSRF 防护、XSS 过滤、SQL 注入防护、密码哈希机制,直接省掉了自己造轮子的风险。对于一个课程设计级别的项目来说,能开箱即用地满足这些安全需求,是很加分的。
第三是生态和资料。Django 的官方文档质量极高,遇到问题随便一搜就能找到解决方案。对于做课程设计的同学来说,这意味着你卡住的时候不会孤立无援。
1.2 系统功能模块怎么拆
拿到需求后不要急着写代码,先把功能模块理清楚。我当时把系统拆成了五个核心模块,分别对应不同角色和业务场景。
用户认证与权限管理模块是系统的地基,负责用户的注册、登录、登出,以及操作权限控制。在医药系统里,管理员和普通员工能做的事情不一样,管理员可以管理用户、查看全部数据,普通员工只能操作日常业务流程。
药品信息管理模块是整个业务的核心,负责药品基本信息的增删改查,包括药品名称、批准文号、生产厂家、规格、剂型、有效期等字段。这部分我会在下面的数据库设计里详细展开。
库存管理模块处理药品的入库、出库和库存查询,关键是库存数量的动态更新和低库存预警。比如某款药品库存低于设定的安全阈值,系统要能自动提醒。
供应商管理模块记录供应商的基本信息和历史合作记录,方便后续对供应商进行评估。
销售与出库管理模块负责创建销售单据,联动扣减库存,同时记录每一笔操作的操作者,方便日后审计。
模块拆分这件事看上去简单,但决定了后面代码的复杂度。我见过不少人把药品和库存塞在一个模型里,结果每次出库入库都要小心翼翼地处理字段同步,逻辑极其容易出错。正确的做法是把药品基础数据和库存数据分开。
1.3 Django 项目目录规划
项目目录不是随便建的,合理的目录结构能让代码维护轻松一个量级。我采用的目录结构如下:
medicine_project/ ├── manage.py ├── medicine_system/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ ├── wsgi.py │ └── asgi.py ├── apps/ │ ├── users/ │ ├── drugs/ │ ├── inventory/ │ ├── suppliers/ │ └── sales/ ├── static/ ├── media/ ├── templates/ │ ├── base.html │ ├── users/ │ ├── drugs/ │ ├── inventory/ │ ├── suppliers/ │ └── sales/ ├── db.sqlite3 └── requirements.txt我把不同业务模块拆成了独立的 app(应用),而不是把所有模型塞在一个 app 里。这样做的好处是各个模块之间的边界清晰,一个 app 只负责一类业务。虽然 Django 官方对 app 的划分没有强制要求,但项目一大,模块拆分的优势就体现出来了。
ivorie 规划好之后,下一步就是搭数据库。医药信息管理系统的难点不在 Django 代码,而在数据模型的设计。
2. 数据库设计与 ORM 模型实现
2.1 核心数据表的字段规划
数据库设计是整个项目最重要的一环,字段设计得不好,后面写业务代码会处处受制。我当时反复推敲了几张核心表的设计,这里把字段和设计理由一并写出来。
药品信息表是系统的核心表,我设计的字段包括药品名称、通用名、批准文号、生产厂家、规格、剂型、单位、零售价、进货价、有效期、存储条件。批准文号是医药行业里药品的唯一标识,类似于人的身份证号,在数据库里应该设置为唯一约束,防止重复录入。
库存表不单独存一个“当前库存”字段,而是记录每次入库和出库的流水。这样设计的好处是你随时可以追溯“某个批次进了多少、出了多少、现在还剩多少”,而不是只知道一个最终数值。如果真的需要实时库存,可以通过聚合函数算出来,或者定时把计算结果同步到一张汇总表。
供应商表记录供应商编号、名称、联系人、联系电话、地址、经营许可证号。其中经营许可证号应该做唯一约束,因为一个合规的供应商只有一个合法证号。
销售单据表记录每一次销售行为,分为单据主表和明细表。主表存单据编号、销售员、销售时间、总金额,明细表存每种药品的数量、单价、小计。
说实话,在设计数据库时我是照着电商系统的思路来的,因为医药销售和电商销售在业务形态上非常相似:有商品、有库存、有订单、有订单明细。电商系统经过这么多年的发展,数据架构已经很成熟,照着它的思路做基本不会出错。
2.2 Django 模型代码示例
数据表设计好了之后,直接用 Django ORM 定义模型。这里给出部分核心模型代码,完整的代码在配套源码里。
from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): """自定义用户模型""" phone = models.CharField(max_length=11, verbose_name='手机号') role = models.CharField(max_length=10, choices=( ('admin', '管理员'), ('staff', '员工'), ), default='staff', verbose_name='角色') class Meta: db_table = 'sys_user' verbose_name = '用户' verbose_name_plural = verbose_name def __str__(self): return self.usernamefrom django.db import models class Drug(models.Model): """药品信息表""" drug_code = models.CharField(max_length=20, unique=True, verbose_name='药品编码') name = models.CharField(max_length=100, verbose_name='药品名称') generic_name = models.CharField(max_length=100, verbose_name='通用名') approval_number = models.CharField(max_length=50, unique=True, verbose_name='批准文号') manufacturer = models.CharField(max_length=100, verbose_name='生产厂家') specification = models.CharField(max_length=50, verbose_name='规格') dosage_form = models.CharField(max_length=20, verbose_name='剂型') unit = models.CharField(max_length=10, verbose_name='单位') purchase_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='进货价') retail_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='零售价') expiry_date = models.DateField(verbose_name='有效期') storage_condition = models.CharField(max_length=50, verbose_name='存储条件') created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间') class Meta: db_table = 'drug_info' verbose_name = '药品信息' verbose_name_plural = verbose_name def __str__(self): return self.nameclass InventoryRecord(models.Model): """库存流水记录表""" RECORD_TYPE = ( ('in', '入库'), ('out', '出库'), ) drug = models.ForeignKey(Drug, on_delete=models.CASCADE, verbose_name='药品') record_type = models.CharField(max_length=10, choices=RECORD_TYPE, verbose_name='记录类型') quantity = models.IntegerField(verbose_name='数量') operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name='操作人') created_at = models.DateTimeField(auto_now_add=True, verbose_name='操作时间') class Meta: db_table = 'inventory_record' verbose_name = '库存流水' verbose_name_plural = verbose_name def __str__(self): return f'{self.drug.name} - {self.get_record_type_display()}'注意几个细节,药品批准文号设置了 unique=True,防止同一款药品重复录入;外键字段用 on_delete=models.SET_NULL 而不是 CASCADE,因为销售记录是审计数据,不能因为用户被删除就跟着删掉底账;价格字段用 DecimalField 而不用 FloatField,因为浮点数在涉及金额时会有精度问题。
2.3 数据库迁移实操记录
模型定义好之后,需要生成并执行迁移脚本。顺序不能乱,命令一共三条:
python manage.py makemigrations python manage.py migrate第一条命令是根据模型的变化生成迁移文件,第二条是把迁移文件真正应用到数据库。有一点要特别注意:如果你启用了 Django Admin,第一次 migrate 时会自动创建用户、权限、日志等内置表,所以要在 migrate 完成之后再创建超级用户:
python manage.py createsuperuser我实际操作中遇到过一个比较坑的情况:模型字段改了,但迁移命令一直报错。排查半天发现是之前有一次 makemigrations 生成的迁移文件有残留冲突,解决办法是把出问题的 app 迁移文件删掉重来。但如果数据库里已经有真实数据,就不要随便删迁移文件,否则会搞得很难看。正确做法是在模型修改之前规划好字段,减少后续的反复修改。这个项目我改了三版才定稿,每次改完都要同步改前端模板里的表单组件,属于正常但很耗时的迭代过程。
3. 核心业务功能与页面实现
3.1 药品管理的增删改查完整实现
药品管理是所有功能里最核心的,增删改查的逻辑要实现得干净且完整。Django 提供了基于类的视图(CBV)和基于函数的视图(FBV)两种方式,我推荐新手先用 FBV 把逻辑想清楚,再看 CBV 的封装。
这里用 FBV 展示一个药品列表加搜索的完整实现:
from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q from .models import Drug from .forms import DrugForm @login_required def drug_list(request): queryset = Drug.objects.all() keyword = request.GET.get('keyword', '') if keyword: queryset = queryset.filter( Q(name__icontains=keyword) | Q(approval_number__icontains=keyword) | Q(manufacturer__icontains=keyword) ) paginator = Paginator(queryset, 10) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) context = { 'page_obj': page_obj, 'keyword': keyword, } return render(request, 'drugs/drug_list.html', context)这里有几个细节值得展开讲。
登录保护使用的是 login_required 装饰器,用户未登录时会被重定向到登录页,这是 Django 内置的认证机制。搜索功能用 Django ORM 的 Q 对象把多个搜索条件用或(or)关系叠加,实现按名称、批准文号、厂家三个维度的模糊搜索。分页用 Paginator 类,每页显示 10 条数据,模板层通过 page_obj 对象渲染分页导航。
药品的新增和编辑逻辑因为表单提交方式相同,我合并成了同一个视图:
@login_required def drug_edit(request, pk=None): if pk: drug = get_object_or_404(Drug, pk=pk) else: drug = None if request.method == 'POST': form = DrugForm(request.POST, instance=drug) if form.is_valid(): drug = form.save() return redirect('drugs:drug_list') else: form = DrugForm(instance=drug) return render(request, 'drugs/drug_form.html', {'form': form})删除操作我建议保守一点,不要直接物理删除数据。医药系统的数据保存期限是有合规要求的,物理删除后审计查证就无从谈起了。更好的做法是加一个 is_active 字段,删除时只是把状态改掉,这样底账还在,界面上不再展示。如果后台管理确实需要物理删除,到 Django Admin 里去操作就行了。
3.2 库存流水与自动预警功能
库存管理在这个系统里不是普通的增删改查,而是要体现业务闭环。入库、出库操作不能只修改当前库存数字,而是要生成流水记录。
@login_required def inventory_in(request): if request.method == 'POST': drug_id = request.POST.get('drug_id') quantity = int(request.POST.get('quantity')) drug = get_object_or_404(Drug, pk=drug_id) # 新增入库流水 InventoryRecord.objects.create( drug=drug, record_type='in', quantity=quantity, operator=request.user ) messages.success(request, f'{drug.name} 入库 {quantity} {drug.unit} 成功') return redirect('inventory:record_list') drugs = Drug.objects.all() return render(request, 'inventory/inventory_in.html', {'drugs': drugs})出库的逻辑和入库类似,但要额外检查库存是否足够。我在实际开发中写了一个库存检查函数,专门用于判断当前库存是否满足出库数量。这个函数通过聚合求和库存流水表来实现,保证数据一致性。
from django.db.models import Sum def get_drug_stock(drug): """计算指定药品的当前库存""" result = InventoryRecord.objects.filter(drug=drug).aggregate( total_in=Sum('quantity', filter=Q(record_type='in')), total_out=Sum('quantity', filter=Q(record_type='out')) ) total_in = result['total_in'] or 0 total_out = result['total_out'] or 0 return total_in - total_out库存预警的逻辑很简单:给药品表加一个 min_stock 字段,表示最低库存阈值。每次查询药品列表时,比较当前库存和阈值,小于阈值就高亮显示提醒。把预警写成一个独立的函数,可以在多个地方复用,不用重复写逻辑。
3.3 用户权限与操作日志设计
这个系统里用户分为管理员和普通员工,用 Django 内置的权限系统就能实现。我在自定义 User 模型里加了 role 字段来区分角色,视图层用 user.is_authenticated 和 user.role 来控权。
但光控权不够,医药系统对操作审计有要求,谁在什么时间修改了哪个药品、做了入库还是出库,都要能查。这部分我设计了一个操作日志表:
class OperationLog(models.Model): user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name='操作人') action = models.CharField(max_length=50, verbose_name='操作类型') detail = models.TextField(verbose_name='操作详情') ip_address = models.CharField(max_length=20, verbose_name='IP地址') created_at = models.DateTimeField(auto_now_add=True, verbose_name='操作时间') class Meta: db_table = 'operation_log' verbose_name = '操作日志' verbose_name_plural = verbose_name在关键的增删改操作里加一行 OperationLog.objects.create(...) 就能完成记录。管理员可以查看日志列表,普通员工看不到这个菜单。这样设计的成本极低,但让系统一下子有了完整性和可信度。
3.4 前端页面的处理技巧
Django 的前端页面我主要用 Bootstrap 来写,不需要复杂的前端工程化。写快速原型时,我直接在基础模板里引入 Bootstrap 的 CDN 文件,布局用栅格系统,表格用样式类,表单用表单组。
模板继承是 Django 模板系统里很重要的特性,把公共部分抽到 base.html 里,子页面只写自己的内容块。
<!-- base.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}医药信息管理系统{% endblock %}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <div class="container"> <a class="navbar-brand" href="#">医药信息管理系统</a> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item"><a class="nav-link" href="{% url 'dashboard' %}">首页</a></li> <li class="nav-item"><a class="nav-link" href="{% url 'drugs:drug_list' %}">药品管理</a></li> <li class="nav-item"><a class="nav-link" href="{% url 'inventory:record_list' %}">库存管理</a></li> <li class="nav-item"><a class="nav-link" href="{% url 'suppliers:supplier_list' %}">供应商管理</a></li> <li class="nav-item"><a class="nav-link" href="{% url 'sales:sale_list' %}">销售管理</a></li> </ul> <ul class="navbar-nav ms-auto"> <li class="nav-item"><span class="nav-link">{{ request.user.username }}</span></li> <li class="nav-item"><a class="nav-link" href="{% url 'logout' %}">退出登录</a></li> </ul> </div> </div> </nav> <div class="container mt-4"> {% if messages %} {% for message in messages %} <div class="alert alert-{{ message.tags }}">{{ message }}</div> {% endfor %} {% endif %} {% block content %}{% endblock %} </div> </body> </html>列表页面的表格加几个字段就够用了,药品名称、编码、厂家、规格、库存、价格、操作按钮。表单页面用 Django 表单渲染,减少手写 HTML 的工作量,也天然支持表单验证。
4. 部署流程与常见问题速查
4.1 本地运行和数据库迁移实操
拿到源码之后,第一步是搭建运行环境。我用的是虚拟环境方案,避免依赖包冲突:
python -m venv venv source venv/bin/activate # Windows 下改为 venv\Scripts\activate pip install -r requirements.txtrequirements.txt 里的核心依赖是 Django 和 mysqlclient(如果数据库用 MySQL),如果用的是项目自带的 sqllite,则不需要额外安装数据库驱动。
settings.py 里对数据库做如下配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'medicine_db', 'USER': 'root', 'PASSWORD': 'your_password', 'HOST': '127.0.0.1', 'PORT': '3306', } }如果本地没有 MySQL,直接用 Django 默认的 SQLite 也可以跑起来,在 settings.py 里把 ENGINE 改为 django.db.backends.sqlite3 即可,不用做其他额外配置。SQLite 对课程设计来说完全够用,等需要部署上线再切换 MySQL。
4.2 部署到服务器的关键步骤
本地跑通之后部署到服务器,我用的是 Windows + waitress + nginx 的组合,或者 Linux + gunicorn + nginx 的组合。前者比较适合 Windows 环境,后者更通用。
在 Linux 上部署的核心步骤如下:
首先收集静态文件,Django 本身不负责处理静态文件的线上托管,需要执行:
python manage.py collectstatic然后在 settings.py 里设置:
DEBUG = False ALLOWED_HOSTS = ['你的域名或IP'] STATIC_ROOT = '/path/to/staticfiles/'再用 gunicorn 启动应用:
pip install gunicorn gunicorn medicine_system.wsgi:application --bind 0.0.0.0:8000最后配置 nginx 反向代理和静态文件服务。nginx 的配置片段大致长这样:
server { listen 80; server_name your_domain.com; location /static/ { alias /path/to/staticfiles/; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }4.3 常见问题排查与避坑经验
我在开发和部署过程中遇到最多的问题基本集中在下面这几类,可以做个速查:数据库连接报错、静态文件加载失败、部署后页面白屏、模板变量访问不到数据、时区导致的时间不对。
数据库连接报错大部分是因为 MySQL 服务没启动或者账号密码错误。确认方法很简单,先尝试用数据库客户端手动连接,能连上再去排查 Django 配置。
静态文件加载失败几乎是每个新手都会踩的坑。开发模式(DEBUG=True)下要用 django.contrib.staticfiles 提供的静态文件服务,模板里用 {% load static %} 和 {% static 'css/style.css' %} 来引用静态文件,而不是写死路径。
部署后页面白屏有个很容易被忽略的原因:ALLOWED_HOSTS 没有把域名或 IP 加进去,Django 直接拒绝处理请求。看到 DisallowedHost 报错就知道是这个问题。
模板里取不到数据的情况,多半是 context 变量名和模板里写的不一致。Django 模板渲染对不存在的变量名不会直接报错,而是渲染为空字符串,肉眼排查起来特别费劲。我的办法是先在视图函数里打印 context,确认数据确实传到模板了,再去对比模板里的变量名。
时区问题是在 settings.py 里设置 TIME_ZONE 和 USE_TZ。国内项目建议设置 TIME_ZONE = 'Asia/Shanghai',如果 USE_TZ = True,Django 存储的是 UTC 时间,模板显示时再转换成当前时区。如果不希望有这种转换逻辑,直接 USE_TZ = False,统一用本地时间。
4.4 源码阅读顺序与二次开发建议
如果你拿到的是别人写好的源码,不要一上来就全局搜索。我建议按下面的顺序去读:
第一步读 requirements.txt 和 README,搞清楚项目依赖哪些第三方库、数据库用的什么、Python 版本要求。第二步读 settings.py,了解项目配置和 app 注册情况。第三步读 urls.py,通过路由表快速了解整个系统的功能入口。第四步读 models.py,理解数据模型和表之间的关系。第五步读 views.py 和 templates,理清业务逻辑和前端渲染的关系。
这里还应该看一下项目中是否有 django 的自定义管理后台配置,admin.py 里的配置能帮你快速了解到系统有哪些核心数据需要管理,也方便你在开发阶段通过后台直接往库里加数据。
二次开发的时候,优先在现有 app 里扩展,不要动不动就新建 app。如果要在药品表上加一个“药品分类”字段,先看现有的 Drug 模型能不能直接加字段、做迁移,而不是重新设计一张分类表把简单问题复杂化。当然,如果分类确实有独立的业务属性,比如分类名称、分类编码、上级分类,那就值得单独建模型。
5. 数据库脚本与文档编写要点
5.1 SQL 脚本的生成与使用场景
项目附件里通常包含一个 .sql 文件,这是数据库的初始化脚本。Django 项目一般不需要手写 SQL,直接用 migrate 生成表结构就行,但考虑到课程设计提交时老师可能会直接查看 SQL 文件,我会额外导出一份 SQL 脚本备用。
导出 SQL 的命令:
python manage.py dumpdata > data.json导出数据表结构可以这么操作:
# SQLite 数据库导出 sqlite3 db.sqlite3 .dump > database.sql如果是 MySQL,可以使用 mysqldump 命令导出。拿到 SQL 脚本后,在文档中说明数据库的导入方式即可,例如:
-- 创建数据库 CREATE DATABASE medicine_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 导入数据 USE medicine_db; SOURCE database.sql;5.2 系统说明文档怎么组织
文档是课程设计报告中很重要的一部分,也是很多人最容易忽视的部分。我提交这个项目时,文档严格按照下面几个章节组织:项目介绍、开发环境说明、系统功能分析、数据库设计、核心代码说明、系统运行步骤、测试报告、总结与展望。
数据库设计部分要画出 E-R 图,并把每张表的主要字段列成表格。核心代码说明部分不贴大段代码,而是挑关键功能的实现思路和代码片段。运行步骤要写得足够傻瓜,能让老师直接照做成功运行,不让对方卡在环境配置这种环节上。
文档的详略安排要合理,不要流水账,更不要大段贴没用的代码。我见过有些同学把模板里的 HTML 一次性贴了三四百行,完全没有解释,这种文档对读者来说没有意义。好的文档是能清晰回答“为什么这么设计”和“怎么运行起来”这两个问题的,而不是简单罗列代码。
5.3 课程设计答辩时的高频问题
课程设计完成后,答辩或演示环节老师通常会抓着几个关键点提问,提前准备好这些问题的答案,会给你增加不少印象分。
第一个问题必然是这个系统采用了什么技术架构?要能流畅说出 Django MTV 架构的含义:M 是 Model 数据模型层,负责与数据库交互;T 是 Template 模板层,负责页面展示;V 是 View 视图层,负责业务逻辑处理和数据传递。
第二个问题是项目中的难点是什么,你是怎么解决的?我的回答是库存流水与库存实时计算的一致性,解决方式是通过库存流水表记录每一次变动,用聚合查询实时汇总当前库存,保证数据可追溯、不会出现账实不符。
第三个问题是这个系统相比传统人工管理有什么优势?从效率提升、错误减少、数据追踪、库存预警方面来谈就可以,这个比较直接。
第四个问题涉及到系统能怎么扩展,比如增加采购管理模块、药品有效期预警、报表导出这些方向都值得提,说明你有继续迭代的意识。
6. 写在最后的一点心得
从项目立项到最终交付,我最大的体会是:这类信息管理系统的核心不在框架用得多花哨,而在数据模型设计得是否扎实。一张合理的数据表结构能帮你省掉后面无数次的代码返工,所以在数据库设计阶段多花时间推敲字段和外键关系,比在视图层反复改逻辑要高效得多。
如果你是在校学生,拿着这份源码做课程设计,建议不要只知道照抄运行,而是把每个模块都过一遍逻辑,能改一处小功能就自己改一处。哪怕只是把搜索的关键字改成厂家编号,这个过程中对 Django 查询语法的理解都会上一个台阶。
如果你是在职开发者,这套项目的价值在于它演示了一个完整业务系统从零到一的开发思路。Django 的脚手架能力很强,但真正的业务逻辑是脚手架给不了的,需要你根据需求反复斟酌。
最后一个实用小建议:开发过程中务必定期提交代码,用 Git 管理版本。医药信息管理系统这种项目,改一版需求后代码基本就改了一半,没有版本管理的话很容易翻车,有了 Git 才能放心地大胆重构。