
简介这是一套面向计算机专业本科生及Django初学者的商品进销存管理系统实战项目源码适用于课程设计、期末大作业或Web开发入门实践。系统基于Python 3.x与Django框架构建完整覆盖商品管理、采购入库、销售出库、库存查询、员工权限控制等核心业务模块具备前后端分离雏形与响应式界面。压缩包共2000个文件主体为1623个JavaScript交互逻辑文件、261个HTML页面模板、51个CSS样式文件含bootstrap、font-awesome、ui等主流UI库辅以少量Python后端视图与配置文件整体体积仅6.08MB轻量易部署。目前已有120人学习下载资源经作者严格调试数据库文件SQLite已预置测试数据开箱即用避免环境配置与数据初始化常见坑点。读者可直接运行并深入理解Django MTV架构、ORM操作、表单处理、静态资源组织及典型业务流程闭环设计。1. 项目概述从零到一构建一个企业级进销存系统最近在整理硬盘时翻出了一个几年前带学生做毕业设计时留下的“高分项目”——一个基于Django的完整商品销售进销存系统。这个项目麻雀虽小五脏俱全涵盖了从供应商管理、商品入库、销售出库、库存盘点、报表统计到用户权限控制的全流程。对于很多想从“增删改查”CRUD练习跨越到真实业务系统开发的Python学习者或者中小企业的技术负责人寻找一个轻量、可二次开发的管理系统原型来说这类项目具有极高的参考价值。它不仅仅是一堆源码和SQL文件更是一个理解Web应用分层架构、业务逻辑设计与数据库建模的绝佳样本。这个系统核心解决的是中小型商贸企业或门店最头疼的库存与资金流管理问题。传统手工记账或Excel表格管理在商品种类增多、进出库频繁后极易出现数据不准、账实不符、查询统计困难的情况。一个自动化的进销存系统能将采购、销售、库存变动实时联动确保每一笔业务都清晰可追溯库存数量、成本、利润自动计算为经营决策提供即时数据支持。使用Django框架来实现意味着你可以快速获得一个结构清晰、易于维护、且自带强大后台管理功能的基础把更多精力投入到业务规则的定制上。接下来我将以这个“高分项目”为蓝本结合我多年开发此类系统的经验为你深度拆解其设计思路、技术实现细节、以及那些在教科书和简单教程里不会提及的“坑”与技巧。无论你是想学习Django全栈开发还是需要为自己的生意或客户定制一个管理系统这篇文章都能提供一条清晰的路径和大量可直接复用的经验。2. 系统核心架构与设计思路拆解2.1 业务模型抽象理解进销存的本质在动手写代码之前必须先把业务逻辑理清。进销存顾名思义就是“进货采购”、“销售出货”、“存货库存”的管理。但其核心远不止三个名词而是围绕“商品”和“资金”流动的一系列状态变换和规则。首先我们需要建立几个核心实体模型商品Product系统的核心。需要记录名称、规格、单位、条形码、分类、成本价、销售价、警戒库存等。这里的一个关键设计点是成本计价方式。常见的有“移动加权平均法”和“先进先出法”。对于大多数中小系统实现“移动加权平均法”更为可行每次采购入库后系统重新计算该商品的平均成本原库存成本本次采购成本/ 总库存数量后续销售出库的成本均按此平均成本计算。这需要在商品模型或单独的库存成本模型中记录平均成本价。库存Stock这不是一个简单的“商品-数量”表。库存是一个动态视图其数量 所有采购入库数量 - 所有销售出库数量 所有库存调整盘盈盘亏数量。因此我们通常不设计一个直接更新的“库存表”而是通过流水单据来驱动库存变化。单据Document这是系统的灵魂。所有库存变动必须“有单可依”。主要单据类型包括采购入库单PurchaseOrder关联供应商包含商品、数量、单价、总金额。审核通过后增加库存并可能影响商品平均成本。销售出库单SalesOrder关联客户包含商品、数量、单价、总金额。审核通过后减少库存。库存调拨单TransferOrder用于仓库之间的商品转移。盘点单StocktakeOrder定期核对实际库存与系统库存产生盘盈实际多或盘亏实际少记录并生成调整单据以同步系统数据。往来单位Partner包括供应商Supplier和客户Customer。统一抽象为“伙伴”共用基础信息字段再用类型字段区分。财务流水Transaction记录与采购、销售相关的收款、付款情况可与单据关联用于统计应收应付。设计思路的核心原则是库存数量只由审核生效的业务单据驱动禁止任何直接修改库存数量的后台操作。这保证了数据的可审计性和一致性。2.2 技术栈选型为什么是Django面对一个管理系统的需求技术选型有很多如Flask 独立前端、FastAPI等。但这个项目选择Django是基于其“开箱即用”的全栈特性和极高的开发效率尤其适合业务逻辑复杂、需要快速构建后台的管理类应用。自带强大的ORM对象关系映射Django ORM让你用Python类来定义数据模型无需编写复杂的SQL语句。这对于进销存系统中复杂的多表关联查询如“查询某个商品的所有入库记录”非常友好。例如定义采购单和采购明细# models.py class PurchaseOrder(models.Model): order_number models.CharField(max_length50, uniqueTrue) # 单号 supplier models.ForeignKey(Partner, on_deletemodels.PROTECT) # 关联供应商 total_amount models.DecimalField(max_digits10, decimal_places2) # 总额 status models.CharField(max_length20, choicesORDER_STATUS_CHOICES, defaultdraft) # 状态草稿、已审核、已完成 created_by models.ForeignKey(User, on_deletemodels.PROTECT) created_at models.DateTimeField(auto_now_addTrue) class PurchaseOrderItem(models.Model): order models.ForeignKey(PurchaseOrder, on_deletemodels.CASCADE, related_nameitems) product models.ForeignKey(Product, on_deletemodels.PROTECT) quantity models.DecimalField(max_digits10, decimal_places2) # 数量支持小数如公斤 unit_price models.DecimalField(max_digits10, decimal_places2) # 单价 total_price models.DecimalField(max_digits10, decimal_places2) # 单项总价通过related_nameitems我们可以用purchase_order.items.all()轻松获取该订单的所有明细项。自动化的Admin后台几行代码就能生成功能完备的数据管理后台在开发初期用于测试数据录入、配置权限非常高效。虽然最终用户界面通常会重写但Admin在项目管理和运维阶段依然价值巨大。健全的身份认证与权限系统进销存系统涉及资金和货物权限控制至关重要。Django自带的auth模块提供了用户、组、权限的完整体系可以精细控制到“某个用户组只能查看销售报表不能审核采购单”。表单与验证Django Form能高效处理前端数据提交、验证和清洗。对于单据录入这种复杂表单场景可以结合ModelForm快速开发。生态与稳定性Django社区庞大遇到任何问题几乎都能找到解决方案。其架构严谨适合构建需要长期维护的企业级应用。注意Django的“重”有时也是缺点对于追求极致微服务或特定高性能API的场景可能不是最优。但对于进销存这类典型的单体复杂业务应用它的综合优势非常明显。2.3 数据库设计要点与陷阱规避数据库设计是系统的基石。除了上述模型对应的表还有一些关键设计和常见陷阱库存如何查询—— 使用视图或聚合查询。 如前所述库存是动态计算的。不建议维护一张实时更新的stock表因为在高并发下更新容易成为瓶颈且易出错。更优的做法是数据库视图View创建一个SQL视图实时联查所有类型的单据明细按商品分组汇总数量。Django可以通过unmanaged model来操作视图。定时物化视图或汇总表对于数据量大的系统实时计算视图可能慢。可以每天定时任务使用Celery或Django-Q计算一次各商品的当前库存存入一张StockSummary表日常查询都走这张表。流水单据的审核操作同步更新该表。这是一种空间换时间的策略。单据编号生成规则。 切忌在代码里用最大值1的方式生成单号并发时会重复。标准做法是使用数据库序列如PostgreSQL的Sequence。使用UUID字段作为主键但展示一个按规则生成的“显示编号”如PO-20231108-0001。这个显示编号的序列部分可以通过一个独立的“编号生成器”表配合数据库事务来安全获取。金额字段与精度。 永远不要使用FloatField存储金额。必须使用DecimalField并明确指定max_digits总位数和decimal_places小数位数。例如max_digits10, decimal_places2表示最大存储99999999.99。软删除与数据完整性。 业务数据如单据不能轻易物理删除。通常采用“软删除”即增加一个is_active或is_deleted布尔字段删除时只是标记。同时外键约束使用on_deletemodels.PROTECT保护模式防止误删关联的主数据如商品被删除后历史单据无法查看。3. 核心功能模块实现详解3.1 商品与库存管理模块这是系统的基石。商品管理除了基本的增删改查重点在于分类和属性的设计。一个灵活的商品分类树可以使用django-mptt库实现和动态规格属性系统能适应从服装颜色、尺码到电子产品型号、配置的不同行业需求。库存管理的核心是提供实时、准确的库存查询接口。基于之前提到的物化视图思路我们可以这样实现# models.py - 库存快照模型 class StockSummary(models.Model): 商品库存每日快照物化视图 product models.OneToOneField(Product, on_deletemodels.CASCADE, primary_keyTrue) # 一对一关联商品 quantity models.DecimalField(max_digits12, decimal_places4, default0, verbose_name当前库存数量) avg_cost models.DecimalField(max_digits10, decimal_places2, default0, verbose_name移动加权平均成本) last_updated models.DateTimeField(auto_nowTrue, verbose_name最后更新时间) class Meta: verbose_name 库存汇总 verbose_name_plural verbose_name # services/stock_service.py - 库存服务层 class StockService: staticmethod transaction.atomic def update_stock_on_order_approval(order_type, order_id): 当采购单或销售单审核通过时更新库存快照 if order_type purchase: order PurchaseOrder.objects.select_related(items).get(idorder_id, statusapproved) for item in order.items.all(): summary, created StockSummary.objects.select_for_update().get_or_create(productitem.product) # 计算新的平均成本: (旧总成本 本次采购总成本) / (旧数量 本次数量) old_total_value summary.quantity * summary.avg_cost new_total_value old_total_value item.total_price new_total_quantity summary.quantity item.quantity new_avg_cost new_total_value / new_total_quantity if new_total_quantity 0 else 0 # 更新库存快照 summary.quantity new_total_quantity summary.avg_cost new_avg_cost summary.save() # 同时记录一条库存变动流水用于对账和追溯 StockFlow.objects.create(...) elif order_type sales: # 销售出库减少库存数量平均成本不变 ...这个服务类封装了库存更新的核心逻辑并在数据库事务中执行确保数据一致性。select_for_update()是行锁防止同时更新同一商品库存时发生并发错误。3.2 采购与销售流程闭环采购和销售流程本质相似都是“创建草稿 - 填写明细 - 提交审核 - (审核通过/驳回) - 生效后更新库存和财务”。实现时需要注意状态机管理单据状态草稿、待审核、已审核、已完成、已取消的流转必须有严格控制。可以使用django-fsm有限状态机库来优雅地管理状态和约束状态转换条件。明细行编辑前端通常需要动态增删明细行。后端API设计应能接收一个商品ID和数量的列表在服务端进行验证如商品是否存在、库存是否充足-针对销售单并批量创建明细对象。审核权限审核操作必须与创建操作权限分离。可以利用Django的permission_required装饰器或基于类的视图的PermissionRequiredMixin来实现。钩子函数审核通过时除了调用上述StockService更新库存还应触发其他动作如生成应付款记录采购、生成应收款记录销售、发送通知等。这些逻辑最好放在模型的save方法信号post_save或服务层的方法中保持代码清晰。一个典型的采购单创建与审核视图示例# views.py from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.views.generic import CreateView from django.urls import reverse_lazy class PurchaseOrderCreateView(LoginRequiredMixin, CreateView): model PurchaseOrder form_class PurchaseOrderForm template_name purchase/order_form.html success_url reverse_lazy(purchase-order-list) def form_valid(self, form): # 将当前用户设置为制单人 form.instance.created_by self.request.user # 生成单号应在form.save()前调用一个生成单号的函数 form.instance.order_number generate_order_number(PO) response super().form_valid(form) # 这里可以处理前端传来的明细行JSON数据创建PurchaseOrderItem items_data json.loads(self.request.POST.get(items, [])) for item in items_data: PurchaseOrderItem.objects.create(orderself.object, ...) return response class PurchaseOrderApproveView(LoginRequiredMixin, PermissionRequiredMixin, View): permission_required inventory.approve_purchaseorder def post(self, request, pk): order get_object_or_404(PurchaseOrder, pkpk) if order.status ! submitted: return JsonResponse({success: False, message: 单据状态不允许审核}) with transaction.atomic(): order.status approved order.approved_by request.user order.approved_at timezone.now() order.save() # 调用服务层更新库存 StockService.update_stock_on_order_approval(purchase, order.id) # 调用服务层生成财务应付记录 FinanceService.create_payable_on_purchase(order.id) return JsonResponse({success: True, message: 审核成功})3.3 报表统计与数据分析报表是管理系统的价值输出。进销存系统常见的报表包括库存报表当前库存列表、低于安全库存的商品、库存周转率分析。销售报表按时间日/月/年、商品、客户统计的销售额、毛利。采购报表供应商采购排行、采购价格趋势。利润分析报表销售收入 - 销售成本基于移动平均成本计算 - 费用。实现报表的关键在于高效的数据库查询和适当的数据聚合。Django ORM的annotate()和aggregate()函数是利器但对于复杂的多维度分析直接编写优化过的SQL或使用数据库的窗口函数可能更高效。例如计算“月度销售毛利”# 使用Django ORM (可能较慢但清晰) from django.db.models import Sum, F, FloatField, ExpressionWrapper from django.db.models.functions import TruncMonth monthly_profit SalesOrderItem.objects.filter( order__statusapproved, order__created_at__year2023 ).annotate( monthTruncMonth(order__created_at), costF(quantity) * F(product__stock_summary__avg_cost), # 关联到库存快照获取成本 revenueF(quantity) * F(unit_price) ).values(month).annotate( total_revenueSum(revenue), total_costSum(cost), total_profitExpressionWrapper(Sum(revenue) - Sum(cost), output_fieldFloatField()) ).order_by(month)实操心得对于大数据量的报表不要在前端请求时实时计算。应采用“预聚合”策略通过定时任务如Celery Beat在每天凌晨计算好常用的聚合数据如每日销售总额、毛利存入ReportDailySummary这样的报表模型。前端查询时直接读取预计算的结果性能极佳。这就是典型的“用空间换时间”和“读写分离”思想在业务系统中的应用。3.4 权限设计与前端界面Django自带的权限系统是基于模型的add, change, delete, view。对于进销存我们需要更细粒度的权限如“审核采购单”、“查看利润报表”。这可以通过两种方式扩展自定义权限Recommended在模型的Meta类中定义自定义权限。class PurchaseOrder(models.Model): ... class Meta: permissions [ (approve_purchaseorder, Can approve purchase order), (view_purchaseorder_report, Can view purchase order report), ]然后通过Admin或代码将权限分配给用户或组。使用第三方库如django-guardian提供对象级别的权限控制例如用户A只能管理自己创建的采购单。前端界面对于此类后台管理系统推荐使用现成的AdminLTE、Tabler等后台模板配合Bootstrap和jQuery快速搭建。如果想获得更现代化的体验可以采用前后端分离架构后端提供RESTful API使用Django REST framework前端使用Vue.js或React。本项目源码为了保持完整性和易于学习很可能使用的是Django模板语言DTL渲染的多页面应用这对于理解和掌握Django的全栈能力非常有帮助。4. 项目部署与运维实战4.1 本地开发环境搭建拿到源码后的第一步是搭建环境。通常项目根目录会有一个requirements.txt文件。# 1. 创建并激活虚拟环境强烈推荐 python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 2. 安装依赖 pip install -r requirements.txt # 3. 配置数据库 # 查看settings.py中的DATABASES设置通常是SQLite开发用或PostgreSQL。 # 如果是SQLite无需额外配置。如果是PostgreSQL需先安装pg创建数据库用户和库。 # 然后运行迁移命令创建数据表 python manage.py migrate # 4. 创建超级用户用于登录Admin后台 python manage.py createsuperuser # 5. 导入初始数据如果项目提供了fixture文件或SQL脚本 python manage.py loaddata initial_data.json # 示例 # 或 python manage.py dbshell db_dump.sql # 6. 运行开发服务器 python manage.py runserver访问http://127.0.0.1:8000/admin/使用超级用户登录检查后台数据是否正常。再访问前端页面通常是根路径/。4.2 生产环境部署要点将Django项目部署到生产环境如Linux服务器需要考虑更多因素Web服务器Django自带的runserver仅用于开发。生产环境必须使用Gunicorn或uWSGI作为应用服务器。反向代理使用Nginx或Apache作为反向代理处理静态文件、SSL加密、负载均衡。数据库将SQLite换成PostgreSQL或MySQL。PostgreSQL在数据一致性和复杂查询支持上更胜一筹。静态文件与媒体文件使用python manage.py collectstatic收集静态文件并由Nginx直接提供。媒体文件用户上传应配置到专门的目录并通过Nginx提供访问或使用云存储如AWS S3、阿里云OSS。环境变量绝对不要将SECRET_KEY、数据库密码等敏感信息硬编码在settings.py中。使用python-decouple或django-environ库从环境变量读取。HTTPS使用Let‘s Encrypt免费证书为域名启用HTTPS保障数据传输安全。一个简化的Gunicorn Nginx配置示例# 使用Gunicorn启动Django (在项目根目录) gunicorn --workers 3 --bind 0.0.0.0:8000 your_project.wsgi:application # Nginx配置片段 (在 /etc/nginx/sites-available/your_project) server { listen 80; server_name your_domain.com; return 301 https://$server_name$request_uri; # 强制跳转HTTPS } server { listen 443 ssl; server_name your_domain.com; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location /static/ { alias /path/to/your/project/staticfiles/; # collectstatic后的路径 } location /media/ { alias /path/to/your/project/media/; } location / { proxy_pass http://127.0.0.1:8000; # 转发给Gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }4.3 数据备份与恢复策略业务数据是无价的。必须建立定期备份机制。数据库备份PostgreSQL: 使用pg_dump命令定期备份。pg_dump -U username -h localhost dbname backup_$(date %Y%m%d).sql使用django-dbbackup等第三方库自动化备份到远程存储如云盘。媒体文件备份使用rsync同步到备份服务器或云存储。备份周期根据数据变更频率每日或每周进行全量备份。保留多个历史版本。恢复演练定期测试备份文件的可恢复性确保在灾难发生时能真正用上。5. 常见问题排查与性能优化5.1 开发与调试阶段常见问题数据库迁移冲突多人开发时经常遇到迁移文件冲突。解决方法是仔细比对迁移文件必要时回滚迁移、删除冲突的迁移文件重新生成。# 查看迁移状态 python manage.py showmigrations # 回滚到指定迁移 python manage.py migrate app_name migration_name # 删除app/migrations/下冲突的迁移文件除了__init__.py # 重新生成迁移 python manage.py makemigrations python manage.py migrate静态文件404开发时DEBUGTrueDjango会托管静态文件。生产环境DEBUGFalse后静态文件失效。务必确保正确执行了collectstatic并且Nginx/Apache配置正确指向了STATIC_ROOT目录。时区问题Django中建议始终使用TIME_ZONE Asia/Shanghai根据你所在时区并在数据库中使用UTC时间USE_TZ True。模板和表单中显示时Django会自动转换。确保服务器操作系统时区也设置正确。“CSRF verification failed”在提交POST表单时遇到。确保模板中的表单使用了{% csrf_token %}标签。如果是前后端分离的API可能需要使用csrf_exempt装饰器或配置DRF的认证方式。5.2 性能瓶颈分析与优化随着数据量增长系统可能会变慢。以下是一些优化方向数据库查询优化这是最常见的瓶颈。使用select_related和prefetch_related避免在循环中进行多次数据库查询N1问题。例如在列出采购单及其供应商时# 糟糕的写法每条订单都会单独查询一次供应商 orders PurchaseOrder.objects.all() for order in orders: print(order.supplier.name) # 每次循环都查询数据库 # 优化写法一次性关联查询 orders PurchaseOrder.objects.select_related(supplier).all() for order in orders: # supplier信息已提前取出无需再查 print(order.supplier.name)仅查询需要的字段使用only()或defer()来限制查询的字段特别是当表中有大文本字段时。建立合适的索引在经常用于查询、过滤WHERE、排序ORDER BY和关联JOIN的字段上建立数据库索引。可以通过Django的db_indexTrue或在迁移中手动创建。缓存策略使用Django的缓存框架将一些不常变化但频繁访问的数据缓存起来如商品分类树、用户菜单权限列表。from django.core.cache import cache def get_product_categories(): categories cache.get(product_categories) if not categories: categories list(Category.objects.all()) # 耗时查询 cache.set(product_categories, categories, timeout3600) # 缓存1小时 return categories分页任何列表查询都必须分页使用Django内置的Paginator或DRF的PageNumberPagination避免一次性加载成千上万条数据。异步任务对于耗时的操作如发送审核通知邮件、生成复杂的报表、执行批量数据导入应该使用异步任务队列如Celery Redis/RabbitMQ。避免阻塞HTTP请求导致用户界面卡顿。5.3 安全加固 checklist关闭Debug模式生产环境务必设置DEBUG False并正确配置ALLOWED_HOSTS。保护Secret Key确保SECRET_KEY通过环境变量设置且不在版本控制中泄露。SQL注入Django ORM已有效防止但如果你必须使用原生SQL务必使用参数化查询cursor.execute(sql, [params])绝不要拼接字符串。XSS跨站脚本Django模板默认自动转义变量但如果你使用|safe过滤器或在前端框架中直接渲染用户输入需格外小心。CSRF保护确保所有修改数据的POST、PUT、DELETE请求都携带CSRF token。文件上传限制上传文件的类型通过MIME类型和文件扩展名双重检查、大小并将上传的文件存储在Web根目录之外通过服务器如Nginx代理访问。权限检查在视图层和模板层都要进行权限验证。不要相信前端传来的任何数据后端必须对每次操作进行权限复核。6. 从项目源码学习到二次开发拿到一个完整的项目源码如何最高效地学习和改造它先跑起来按照第4.1节的步骤让项目在本地成功运行。这是理解项目结构的基础。阅读models.py数据模型是业务的基石。仔细阅读每个模型类理解字段含义和关联关系。画出简单的ER图实体关系图帮助理解。追踪一个核心流程选择一个完整流程比如“创建采购单 - 审核 - 库存更新”从URL路由urls.py开始追踪到视图views.py再到模板templates/或序列化器serializers.py最后到模型和服务层。这是理解代码组织方式的最佳路径。分析Admin配置查看admin.py了解后台如何管理这些模型这能快速帮你建立数据的增删改查界面。定制化开发修改业务逻辑通常集中在views.py、forms.py和自定义的services.py或utils.py中。增加新功能模仿现有模块的结构。创建新的模型、视图、URL和模板。更换前端界面如果你想用Vue/React重写前端可以将Django项目转型为纯后端API。使用django-rest-framework快速构建RESTful API原有的模型和业务逻辑大部分可以复用。编写测试在修改代码前如果原项目有测试先运行它们。为你新增或修改的功能编写单元测试tests.py这是保证代码质量、避免回归错误的生命线。这个基于Django的进销存系统项目是一个绝佳的学习范本和创业起点。它清晰地展示了如何将一个复杂的业务需求通过合理的分层设计模型、视图、模板、服务转化为可工作的软件。通过深入研读和动手实践你不仅能掌握Django开发的各项技能更能获得处理真实业务逻辑的宝贵经验。在实际部署和使用过程中你可能会遇到文中未提及的特定问题那时Django丰富的文档和活跃的社区将成为你强大的后盾。记住最好的学习方式就是去用、去改、去解决真实的问题。本文还有配套的精品资源点击获取