Django汉服租赁系统:订单+库存+可视化全栈实战 简介本资源是一套面向计算机专业毕业生与Java学习者的毕设级实战项目聚焦汉服租赁业务场景基于PythonDjango实现具备完整前后端功能的可视化Web系统适用于毕业设计、课程设计及期末大作业。压缩包共725个文件含68个核心Python后端逻辑文件、136个Vue前端组件、159个SVG图标资源、115张JPG商品图及70个JS交互脚本辅以SQL建库脚本、BAT一键运行/安装批处理、CSS样式与JSON配置等整体31.02MB结构清晰、开箱即用。已有47人下载学习资源提供经严格调试可直接运行的源码、详细数据库设计文档、分模块运行说明及系统部署指南。读者可完整掌握Django ORM建模、用户权限管理、订单支付流程、静态资源集成与前后端联调等关键技能并通过源码深入理解传统文化类业务系统的技术落地路径。1. 汉服租赁系统不是PPT演示它真能跑通订单库存可视化三件套毕业设计选它不翻车你手头那份“基于PythonDjango的汉服租赁可视化系统”的毕设资源不是用来凑页数的静态网页截图而是一套可启动、可下单、可查库存、可看图表的完整Web应用——它自带真实数据库SQLite3、前后端分离式模板Bootstrap5 Chart.js、管理员后台Django Admin深度定制、用户租借流程含预约、押金、归还状态流转甚至预留了微信支付对接入口。这不是玩具项目而是我去年帮三个学院同学落地的毕设基线从python manage.py runserver到导出Excel报表全程无硬编码ID、无假数据填充、无前端报错黑屏。适合计算机/软件工程专业本科生尤其适合没做过全栈但会写基础Python、想避开Java环境配置地狱、又需要答辩时能现场演示真实交互的同学。它不炫技但每一步都踩在答辩老师最常问的点上数据怎么存状态怎么变图表怎么联动——这些源码里全有答案。2. 从零跑通Django环境搭建与项目结构解剖2.1 环境准备Python 3.8 pip virtualenv 是底线别碰conda提示本系统严格测试于 Python 3.8.10 和 Django 4.2.7高版本如 Django 5.x会导致django.contrib.admin中list_filter的日期范围筛选器异常低版本Django 3.2则缺失as_view()的kwargs透传能力影响预约单详情页路由。请勿用 conda 创建虚拟环境——其 pip 源常缓存旧版 django-filter导致FilterSet类初始化失败。# 推荐步骤Linux/macOS python3.8 -m venv venv_hanfu source venv_hanfu/bin/activate pip install --upgrade pip pip install -r requirements.txtrequirements.txt核心依赖如下已剔除冗余包仅保留运行必需包名版本作用说明Django4.2.7Web框架核心含Admin、ORM、URL路由django-filter23.4支持后台按“尺码/风格/租赁状态”多条件筛选汉服django-crispy-forms2.0统一渲染表单样式避免Bootstrap5 class手动拼写错误django-extensions3.2.3提供runserver_plus带代码热重载和show_urls调试路由matplotlib3.7.2后台统计图生成非前端Chart.js数据源用于导出PDF报表openpyxl3.1.2导出租赁记录为Excel支持合并单元格与样式注意pip install -r requirements.txt后务必执行python manage.py check确认无SystemCheckError。若提示models.E001: Field defines a relation with the model auth.User说明settings.py中AUTH_USER_MODEL users.CustomUser未生效——这是本项目的关键定制点用户模型继承自AbstractBaseUser新增phone,student_id,deposit_balance字段所有租赁单均关联此模型而非默认auth.User。2.2 项目目录结构看清哪部分改、哪部分不动进入项目根目录后执行tree -L 2 -I venv|__pycache__|mediaWindows可用dir /s /b替代你会看到标准Django结构但有三处必须关注hanfu_rental/ ├── manage.py ├── requirements.txt ├── hanfu_rental/ # 项目配置包settings.py在此 │ ├── __init__.py │ ├── settings.py # ✅ 关键DATABASES配置、STATIC_ROOT、MEDIA_ROOT路径 │ ├── urls.py # ✅ 关键主路由包含admin/、users/、rental/三大命名空间 │ └── wsgi.py ├── users/ # 自定义用户模块✅ 必读 │ ├── __init__.py │ ├── admin.py # ✅ 定制Admin显示phone/student_id禁用密码修改入口 │ ├── apps.py │ ├── models.py # ✅ 核心CustomUser类含deposit_balance字段及余额校验逻辑 │ └── views.py # 登录/注册/个人中心含押金充值页面 ├── rental/ # 租赁业务核心模块✅ 必读 │ ├── __init__.py │ ├── admin.py # ✅ 汉服管理支持按“是否可租”“尺码区间”批量操作 │ ├── apps.py │ ├── models.py # ✅ 四张核心表Costume汉服、RentalOrder订单、RentalItem订单明细、ReturnRecord归还记录 │ ├── views.py # ✅ 订单创建逻辑检查库存、冻结押金、生成订单号格式HF20240512001 │ └── urls.py # 子路由/rental/list/, /rental/order/create/, /rental/order/detail/id/ ├── dashboard/ # 可视化模块✅ 必读 │ ├── __init__.py │ ├── views.py # ✅ 图表数据接口返回JSON格式的{“rentals_by_month”: [...], “costumes_by_style”: [...]} │ └── templates/dashboard/ # 前端模板index.html含Chart.js实例数据通过AJAX加载 └── static/ # 静态资源✅ 修改前先备份 ├── css/ ├── js/ └── images/重点逻辑链用户登录 → 进入/rental/list/查看可租汉服 → 点击“立即预约” → 跳转/rental/order/create/→ 提交后触发views.py中create_order()→ 校验库存 → 扣减Costume.stock→ 冻结CustomUser.deposit_balance→ 生成RentalOrder对象 → 重定向至/rental/order/detail/123/。这个链路在rental/views.py第 87–124 行完整实现没有调用任何外部API纯Django ORM操作。2.3 数据库迁移与初始数据注入别跳过loaddata首次运行前必须执行两步python manage.py makemigrations python manage.py migrate但仅此不够本项目预置了真实业务数据非空数据库fixtures/initial_users.json含1个管理员admin/admin123、3个测试用户student001~003fixtures/initial_costumes.json52件汉服覆盖唐制、宋制、明制尺码S~XL单价80~300元fixtures/initial_orders.json12条历史订单含“已预约”“已取衣”“已归还”“逾期未还”四种状态执行命令注入python manage.py loaddata fixtures/initial_users.json python manage.py loaddata fixtures/initial_costumes.json python manage.py loaddata fixtures/initial_orders.json为什么必须loaddata因为Costume模型中image字段是ImageField其值为相对路径如costume_images/tang_changpao.jpg。loaddata会自动将fixtures/下的图片复制到media/costume_images/目录。若跳过此步前台列表页将显示断裂图片且RentalOrder的total_amount字段依赖Costume.price计算空数据会导致ZeroDivisionError。验证数据是否就位python manage.py shell from rental.models import Costume Costume.objects.count() 52 from users.models import CustomUser CustomUser.objects.get(usernamestudent001).deposit_balance 500.00 # 初始押金500元3. 可视化模块拆解Chart.js如何与Django后端实时联动3.1 数据接口设计dashboard/views.py的JSON输出规范可视化不靠前端硬编码而是由Django提供结构化API。打开dashboard/views.py核心函数是get_chart_data(request)# dashboard/views.py from django.http import JsonResponse from django.db.models import Count, Sum, Q from datetime import datetime, timedelta from rental.models import RentalOrder, Costume def get_chart_data(request): # 1. 按月统计订单量近6个月 six_months_ago datetime.now() - timedelta(days180) monthly_data ( RentalOrder.objects .filter(created_at__gtesix_months_ago) .extra({month: strftime(%%Y-%%m, created_at)}) .values(month) .annotate(countCount(id)) .order_by(month) ) # 2. 按风格统计汉服数量 style_data ( Costume.objects .values(style) .annotate(countCount(id)) .order_by(-count) ) # 3. 当前各状态订单占比 status_counts RentalOrder.objects.values(status).annotate(countCount(id)) total sum(item[count] for item in status_counts) status_ratio { item[status]: round(item[count] / total * 100, 1) if total else 0 for item in status_counts } return JsonResponse({ rentals_by_month: list(monthly_data), costumes_by_style: list(style_data), status_ratio: status_ratio, })关键参数说明extra({month: strftime(%%Y-%%m, created_at)})SQLite专用日期分组语法不可直接用于MySQL/PostgreSQL需改为TruncMonth(created_at)。若换数据库此处必改。status_ratio返回的是百分比数值如pending: 32.5前端Chart.js直接用作data.datasets[0].data。所有查询均使用values()annotate()避免N1查询——实测500条订单下接口响应时间 120ms。3.2 前端图表渲染dashboard/templates/dashboard/index.html的AJAX调用模板中Chart.js初始化代码位于script标签内关键逻辑如下!-- dashboard/templates/dashboard/index.html -- script document.addEventListener(DOMContentLoaded, function() { // 1. 获取数据 fetch(/dashboard/chart-data/) .then(response response.json()) .then(data { // 2. 渲染月度订单图折线图 const ctx1 document.getElementById(monthlyChart).getContext(2d); new Chart(ctx1, { type: line, data: { labels: data.rentals_by_month.map(d d.month), datasets: [{ label: 订单数量, data: data.rentals_by_month.map(d d.count), borderColor: #4e73df, tension: 0.3 }] } }); // 3. 渲染风格分布图环形图 const ctx2 document.getElementById(styleChart).getContext(2d); new Chart(ctx2, { type: doughnut, data: { labels: data.costumes_by_style.map(d d.style), datasets: [{ data: data.costumes_by_style.map(d d.count), backgroundColor: [#4e73df, #1cc88a, #36b9cc] }] } }); }); }); /script避坑点fetch(/dashboard/chart-data/)的路径必须与dashboard/urls.py中path(chart-data/, views.get_chart_data, namechart_data)一致。若误写成/api/chart-data/浏览器控制台将报404图表空白。labels和data数组长度必须严格对应。若后端返回costumes_by_style为空如数据库被清空前端会因map报错导致整个页面JS中断——必须加空值判断// 在 fetch.then() 内添加 if (data.costumes_by_style.length 0) { data.costumes_by_style [{style: 暂无数据, count: 1}]; }3.3 动态刷新机制如何让图表随新订单实时更新本系统未用WebSocket而是采用页面级轮询简单可靠适合毕设!-- 底部添加 -- script // 每30秒刷新一次图表数据 setInterval(() { location.reload(); // 粗暴但有效整页刷新确保状态同步 }, 30000); /script为什么不用AJAX局部刷新因为订单状态变更如用户点击“确认取衣”会触发RentalOrder.status字段更新而get_chart_data()查询的是聚合结果。局部刷新需同时更新多个图表的data属性并重绘代码复杂度陡增。毕设场景下30秒整页刷新对用户体验无感且杜绝了状态不同步风险——这是我带学生答辩时被问到最多的问题直接答“为保障数据一致性采用服务端驱动的整页刷新”比解释WebSocket更稳妥。4. 避坑指南这五个错误让90%的同学卡在部署前4.1 现象python manage.py runserver启动后访问http://127.0.0.1:8000显示ModuleNotFoundError: No module named django.core.management原因虚拟环境未激活或pip install django时未指定-U参数导致安装了 Django 1.x 旧版本项目要求 4.2.7。解决确认which python指向venv_hanfu/bin/python执行pip uninstall django后重装pip install Django4.2.7。4.2 现象登录管理员后台 (/admin) 后汉服列表页显示RelatedObjectDoesNotExist: Costume has no image.原因loaddata未执行或media/目录权限不足Linux/macOS下chmod -R 755 media。Costume.image字段为空时Django Admin 尝试调用image.url抛出异常。解决先执行python manage.py loaddata fixtures/initial_costumes.json再检查media/costume_images/是否存在且含.jpg文件最后在rental/admin.py中为CostumeAdmin添加readonly_fields (image_tag,)并定义image_tag方法处理空值。4.3 现象用户提交预约单时页面跳转到http://127.0.0.1:8000/rental/order/create/并显示CSRF verification failed. Request aborted.原因rental/templates/rental/order_form.html中遗漏{% csrf_token %}或settings.py中MIDDLEWARE顺序错误django.middleware.csrf.CsrfViewMiddleware必须在SessionMiddleware之后、CommonMiddleware之前。解决检查模板第3行是否含{% csrf_token %}核对settings.py中MIDDLEWARE列表确保顺序为django.contrib.sessions.middleware.SessionMiddleware,django.middleware.csrf.CsrfViewMiddleware,django.middleware.common.CommonMiddleware。4.4 现象图表页面空白浏览器控制台报错Uncaught ReferenceError: Chart is not defined原因static/js/chart.min.js文件缺失或base.html中script src{% static js/chart.min.js %}/script路径错误应为static/js/非static/dashboard/js/。解决下载 Chart.js v3.9.1 保存为static/js/chart.min.js确认base.html中引用路径与实际文件位置一致。4.5 现象导出Excel报表时下载的文件打不开提示“文件损坏”原因openpyxl版本过高3.1.2以上与django-excel-response不兼容或rental/views.py中export_excel()函数未设置response[Content-Type] application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。解决降级openpyxl至3.1.2pip install openpyxl3.1.2检查export_excel函数末尾是否有response[Content-Disposition] attachment; filenamerental_report.xlsx——缺少此行会导致浏览器直接渲染Excel二进制流而非下载。5. 进阶技巧用Django Admin定制导出功能三步生成带样式的租赁报表毕设答辩时老师常问“数据能导出吗格式能定制吗”——本系统已内置Excel导出但默认样式简陋。下面教你三步升级为带标题、列宽自适应、状态色标的专业报表。5.1 步骤一在rental/admin.py中扩展CostumeAdmin# rental/admin.py from django.contrib import admin from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from django.http import HttpResponse admin.register(Costume) class CostumeAdmin(admin.ModelAdmin): # ...原有配置... actions [export_as_excel] def export_as_excel(self, request, queryset): # 1. 创建工作簿 wb Workbook() ws wb.active ws.title 汉服库存清单 # 2. 设置表头样式 header_font Font(name微软雅黑, boldTrue, size12) header_fill PatternFill(start_color4e73df, end_color4e73df, fill_typesolid) center_align Alignment(horizontalcenter, verticalcenter) thin_border Border( leftSide(stylethin), rightSide(stylethin), topSide(stylethin), bottomSide(stylethin) ) # 3. 写入表头 headers [编号, 名称, 风格, 尺码, 单价(元), 库存, 状态, 上架时间] for col_num, header in enumerate(headers, 1): cell ws.cell(row1, columncol_num, valueheader) cell.font header_font cell.fill header_fill cell.alignment center_align cell.border thin_border # 4. 写入数据行带状态色标 for row_num, costume in enumerate(queryset, 2): ws.cell(rowrow_num, column1, valuecostume.id) ws.cell(rowrow_num, column2, valuecostume.name) ws.cell(rowrow_num, column3, valuecostume.get_style_display()) # 使用get_FOO_display() ws.cell(rowrow_num, column4, valuecostume.size_range) ws.cell(rowrow_num, column5, valuefloat(costume.price)) ws.cell(rowrow_num, column6, valuecostume.stock) # 状态列绿色可租红色缺货灰色下架 status_cell ws.cell(rowrow_num, column7, valuecostume.get_status_display()) if costume.status available: status_cell.font Font(color007E33) # 绿色 elif costume.status out_of_stock: status_cell.font Font(colorC00000) # 红色 else: status_cell.font Font(color808080) # 灰色 ws.cell(rowrow_num, column8, valuecostume.created_at.strftime(%Y-%m-%d)) # 5. 自动调整列宽 for column in ws.columns: max_length 0 column_letter column[0].column_letter for cell in column: try: if len(str(cell.value)) max_length: max_length len(str(cell.value)) except: pass adjusted_width min(max_length 2, 50) # 限制最大宽度 ws.column_dimensions[column_letter].width adjusted_width # 6. 构建HTTP响应 response HttpResponse( content_typeapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet ) response[Content-Disposition] attachment; filenamehanfu_inventory.xlsx wb.save(response) return response export_as_excel.short_description 导出选中汉服为Excel带样式5.2 步骤二在Admin界面测试导出启动服务python manage.py runserver访问http://127.0.0.1:8000/admin/rental/costume/勾选若干汉服或全选顶部操作栏选择“导出选中汉服为Excel带样式”→ 执行下载的hanfu_inventory.xlsx将自动打开呈现表头蓝底白字居中“状态”列按实际值着色绿色/红色/灰色所有列宽适配内容长度无合并单元格干扰保持数据可筛选5.3 步骤三为订单导出添加“逾期天数”计算列RentalOrder模型中due_date字段定义了应归还日期但Admin默认不显示逾期天数。我们扩展RentalOrderAdmin# rental/admin.py from django.utils import timezone admin.register(RentalOrder) class RentalOrderAdmin(admin.ModelAdmin): # ...原有配置... def overdue_days(self, obj): if obj.status overdue and obj.due_date: delta timezone.now().date() - obj.due_date return f{delta.days}天 return - overdue_days.short_description 逾期天数 # 列标题 overdue_days.admin_order_field due_date # 支持按此列排序 list_display (order_number, user, status, total_amount, created_at, overdue_days)效果在订单列表页新增“逾期天数”列值为数字“天”单位如3天且可点击列头按due_date升降序排列——这比单纯展示日期更直观体现业务风险。从那以后我每次帮学生改毕设只要涉及数据导出都强制走一遍openpyxl样式定制先写表头样式再逐列赋值最后调column_dimensions.width。不是为了炫技而是因为答辩时老师拿起鼠标点开Excel看到带颜色的状态列和自动适配的列宽会自然点头说“嗯考虑得挺细”。希望帮到你。本文还有配套的精品资源点击获取