
简介这是一套基于Python 3.7与Django 2.2.3开发的资产管理系统完整源码包适合正在学习Django框架的开发者以及需要完成毕业设计或课程设计的计算机专业学生。项目涵盖资产管理、分类与位置维护、用户权限控制、Admin后台管理等典型业务模块清晰演示了Django的MVT设计模式、模型迁移、视图与URL配置、模板渲染和表单处理等核心流程。压缩包共1369个文件以JS、CSS、HTML等前端静态资源为主同时包含Python源码、模板配置、SQLite数据库、启动脚本run.bat、AdminLTE后台界面模板以及图片字体等媒体资源整体约15.05MB目录结构完整便于直接运行和二次开发。目前已有158人学习下载。通过该资源可快速理解企业级Web应用的工程组织方式掌握从环境搭建、数据建模、后台开发到部署上线的全栈实践思路是一份兼具教学与实用价值的Django项目范例。1. 拿到压缩包的第一件事先搞清楚它根本不是“源码堆”打开这个基于 python 3.7 django 2.2.3 实现的资产管理系统.zip你会看到run.bat一马当先后面跟着一串adminlte.css、iziModal.min.css、fontawesome.css。这不是普通的静态文件堆砌而是一个已经帮你配好前端皮肤和后端框架的 Django 2.2.3 资产管理系统。它解决的是传统固定资产管理用 Excel 记录导致的“数据不同步、查询靠翻表、权责不清晰”问题把资产信息、分类、位置、状态统一落到数据库里通过 Web 界面进行增删改查。对于正在找课程设计、毕业设计模板或者想在公司内部快速搭一套轻量级 CMDB 的开发者来说这个包的价值在于“可运行、可改造、前端已集成”。最不济它也能当一份 Django 1.x 迁移到 2.2 时代的实战参考。下面我从运行机制讲起逐步拆到模型、视图、模板和部署每一层都会给出可复现的命令和代码。2. 环境选型与一键启动原理Python 3.7 和 Django 2.2.3 到底卡在哪2.1 为什么是这个组合而不是 Django 4.xPython 3.7 引入的dataclasses、改进的nonlocal和字典访问优化让它在 2019 年是“生产级”的版本Django 2.2 是当年的 LTS长期支持版本2.2.3 修复了若干安全漏洞比如反序列化问题。这个组合放在今天仍然能跑而且很多企业内部遗留项目就停在这个栈上。如果你后续要接手这类项目先确认 Python 版本不是 3.8因为 Django 2.2 官方支持到 3.7用 3.9 以上可能会遇到distutils兼容性问题。从运行角度看这个 zip 的核心在于run.bat。它通常做的事情就是激活虚拟环境、检查依赖、执行数据库迁移最后启动开发服务器。常见的写法和我们手动敲命令是等价的。echo off cd /d %~dp0 if not exist venv ( python -m venv venv call venv\Scripts\activate pip install -r requirements.txt ) else ( call venv\Scripts\activate ) python manage.py makemigrations python manage.py migrate python manage.py runserver 0.0.0.0:8000逻辑说明%~dp0获取批处理所在目录保证无论从哪里双击运行工作目录都切换正确虚拟环境不存在时自动创建并安装requirements.txt中锁定的Django2.2.3。每次启动先迁移数据库再启动监听0.0.0.0:8000的服务器这样做是为了避免你手动敲一堆命令。参数说明0.0.0.0表示监听所有网卡局域网内其他机器可以访问如果你只本机调试改成127.0.0.1更安全。2.2 项目结构与静态文件职责zip 里出现的 CSS 文件不是乱放的。adminlte.css和adminlte.min.css对应后台管理框架 AdminLTE 的压缩和未压缩版本iziModal.min.css是弹窗组件样式all.css、fontawesome.css、v4-shims.css属于 FontAwesome 图标库的各个变体。它们被放在static/目录下最终通过模板里的{% load static %}引入。下表列出了这个系统典型的文件结构你解压后应该对照检查路径作用manage.pyDjango 项目操作入口所有命令的起点run.batWindows 一键启动脚本cmdb/主应用存放 models、views、admintemplates/base.html公共骨架集成 AdminLTE 布局static/adminlte/AdminLTE 的 CSS/JS 文件static/fontawesome/图标字体文件static/iziModal/弹窗组件requirements.txt依赖清单含django2.2.3如果你的 zip 里没有requirements.txt请先执行pip install django2.2.3然后看settings.py里INSTALLED_APPS是否注册了cmdb应用。这里最常见的坑是静态文件路径配置# settings.py STATIC_URL /static/ STATICFILES_DIRS [ BASE_DIR / static, ]如果不配置STATICFILES_DIRS模板里的{% static adminlte/adminlte.css %}会直接 404。这也是为什么很多人双击run.bat后页面能用但没有样式的原因。2.3 数据库迁移与初始数据开发阶段默认使用 SQLite它不需要额外安装数据库服务适合课程设计和内部小系统。进入项目根目录后依次执行以下命令python manage.py makemigrations cmdb python manage.py migrate python manage.py createsuperuser逻辑说明makemigrations会把models.py里的变更生成迁移文件migrate将迁移文件应用到db.sqlite3。createsuperuser创建管理员账号之后才能登录 Django Admin 管理资产数据。如果run.bat已经在启动时执行了这些你只需要补建超级用户。3. 资产数据模型设计从 Asset、Category 到 Location 的字段规划3.1 模型之间的关系资产管理系统最核心的是资产表Asset它关联分类Category和位置Location。分类描述“这是什么类的东西”位置描述“东西放在哪”资产表本身记录“这个东西的归属和状态”。这种多对一关系是资产系统的标准做法避免在每条资产记录里重复写字符串也方便按分类和位置做统计。下面是一个可直接运行的models.py示例from django.db import models class Category(models.Model): name models.CharField(max_length50, verbose_name分类名称) def __str__(self): return self.name class Location(models.Model): building models.CharField(max_length100, verbose_name楼栋) room models.CharField(max_length100, verbose_name房间号) def __str__(self): return f{self.building}-{self.room} class Asset(models.Model): name models.CharField(max_length100, verbose_name资产名称) category models.ForeignKey(Category, on_deletemodels.PROTECT, verbose_name分类) location models.ForeignKey(Location, on_deletemodels.SET_NULL, nullTrue, verbose_name位置) sn models.CharField(max_length100, uniqueTrue, verbose_name资产编号) status models.CharField( max_length20, choices[(in_use, 使用中), (idle, 闲置), (repair, 维修中)], defaultidle, verbose_name状态, ) purchase_date models.DateField(verbose_name购买日期) price models.DecimalField(max_digits10, decimal_places2, verbose_name价格) owner models.CharField(max_length50, blankTrue, verbose_name领用人) remark models.TextField(blankTrue, verbose_name备注) def __str__(self): return self.name逻辑说明Category用PROTECT保护分类下如果还有资产删除分类会被阻止避免产生孤儿数据Location用SET_NULL删除位置后资产保留但位置字段置空这在资产报废后删除位置时更友好。DecimalField用于货币金额不能用FloatField否则在求和时会出现浮点误差。3.2 字段与迁移的对照字段类型关键点nameCharField不为空长度 100snCharFieldunique 唯一约束保证资产编号不重复purchase_dateDateField日期格式方便按年份过滤priceDecimalField保留两位小数statusCharField choices限定可选状态设计字段时注意verbose_name是 Django 管理后台和表单自动生成的标签名建议全部写上中文不然后台会显示英文变量名。生成并执行迁移命令与 2.3 节一致只是要确保在models.py所在的 app 下执行python manage.py makemigrations cmdb python manage.py migrate cmdb执行后可以通过sqlite3 db.sqlite3 .schema cmdb_asset查看实际建表语句用于核对索引和约束。3.3 在 Django Admin 中注册和优化Django 自带的后台是这个系统最省力的部分。在cmdb/admin.py中注册三个模型并配置列表展示字段from django.contrib import admin from .models import Asset, Category, Location admin.register(Asset) class AssetAdmin(admin.ModelAdmin): list_display (sn, name, category, location, status, owner) search_fields (sn, name) list_filter (status, category) list_editable (status,)参数说明list_display控制后台列表页显示的列search_fields会生成一个搜索框并对 Sn 和名称做 LIKE 查询list_filter在右侧生成状态和分类筛选条list_editable可以不用进入详情页直接修改状态这对于批量盘点非常好用。注册后登录http://127.0.0.1:8000/admin就能看到资产表。4. 视图、URL 与 AdminLTE 模板的整合流程4.1 路由映射方式在cmdb/urls.py中采用传统 FBV 方式映射视图from django.urls import path from . import views urlpatterns [ path(, views.asset_list, nameasset_list), path(add/, views.asset_add, nameasset_add), path(edit/int:pk/, views.asset_edit, nameasset_edit), path(delete/int:pk/, views.asset_delete, nameasset_delete), ]int:pk是 Django 2.0 以后的 path 转换器它会把 URL 中的数字自动转换成 Python int 类型并在视图函数中作为参数接收。相比旧版正则写法更简洁且类型安全。对应视图函数views.asset_list需要处理分页和搜索from django.core.paginator import Paginator from django.shortcuts import render from .models import Asset def asset_list(request): qs Asset.objects.select_related(category, location).all() keyword request.GET.get(keyword, ) if keyword: qs qs.filter(name__icontainskeyword) paginator Paginator(qs, 10) page_obj paginator.get_page(request.GET.get(page)) return render(request, cmdb/asset_list.html, {page_obj: page_obj})逻辑说明select_related在查询 Asset 的同时用 JOIN 把关联的 Category 和 Location 一次性查出来避免逐条查询产生 N1 问题filter(name__icontainskeyword)实现前后缀模糊搜索。分页器每页 10 条page_obj在模板中可以调用page_obj.has_previous()和page_obj.has_next()控制翻页按钮。4.2 AdminLTE 模板引用方式这个系统采用 AdminLTE 风格模板继承关系为base.html-asset_list.html。base.html中需要先加载静态文件{% load static %} !DOCTYPE html html langzh-hans head meta charsetUTF-8 title{% block title %}资产管理系统{% endblock %}/title link relstylesheet href{% static adminlte/adminlte.css %} link relstylesheet href{% static fontawesome/all.css %} link relstylesheet href{% static iziModal/iziModal.min.css %} /head body {% block content %}{% endblock %} script src{% static iziModal/iziModal.min.js %}/script /body /html注意href{% static ... %}不可写成href/static/...因为前者会根据部署环境自动处理 CDN 或自定义静态服务器 URL。下表是这些 css 在页面中的角色文件模块用途adminlte.css整体布局侧边栏、导航、卡片、表格基础样式all.css图标菜单图标、按钮图标iziModal.min.css弹窗资产详情弹出层style.css自定义覆盖覆盖 AdminLTE 默认颜色和间距asset_list.html中使用page_obj渲染表格{% extends base.html %} {% block content %} div classcard table classtable table-bordered tr th编号/thth名称/thth分类/thth状态/th /tr {% for asset in page_obj %} tr td{{ asset.sn }}/td td{{ asset.name }}/td td{{ asset.category.name }}/td td{{ asset.get_status_display }}/td /tr {% empty %} trtd colspan4暂无数据/td/tr {% endfor %} /table /div div classpagination {% if page_obj.has_previous %} a href?page{{ page_obj.previous_page_number }}上一页/a {% endif %} /div {% endblock %}get_status_display是 Django 对choices字段自动生成的方法返回中文状态而不是存储值。如果页面没有 css优先检查STATICFILES_DIRS是否指向了实际解压目录这个我在 2.2 节已经强调过。4.3 表单提交与 CSRF 防护要实现新增资产模板里必须带上{% csrf_token %}form methodpost action{% url asset_add %} {% csrf_token %} {{ form.as_p }} button typesubmit classbtn btn-primary提交/button /formDjango 2.2.3 默认启用 CSRF 中间件如果不加这个 tokenPOST请求会被 403 拒掉。这里form.as_p由 Django 的 ModelForm 自动渲染字段省去手写每个输入框的 HTML。视图函数里校验逻辑为from django.shortcuts import redirect from .forms import AssetForm def asset_add(request): if request.method POST: form AssetForm(request.POST) if form.is_valid(): form.save() return redirect(asset_list) else: form AssetForm() return render(request, cmdb/asset_form.html, {form: form})form.is_valid()会执行字段非空、类型判断和唯一约束检查只要模型里定义了uniqueTrue重复的sn会被自动拦截。5. 部署到宝塔的要点和二次开发的两个小技巧5.1 用 Gunicorn 和 Nginx 跑起来如果在 Linux 服务器上部署不要直接用run.bat。安装 Python 3.7 后通过宝塔面板的 Python 项目管理器创建虚拟环境然后安装依赖执行pip install gunicorn python manage.py collectstatic --noinput gunicorn cmdb.wsgi:application -b 0.0.0.0:8000 --workers 3参数说明--workers 3表示 3 个 worker 进程对于小系统够用collectstatic会把所有 app 的静态文件复制到STATIC_ROOT指定的目录比如/www/wwwroot/your_project/static_assets。然后在 Nginx 配置中把/static/请求转发到这个目录location /static/ { alias /www/wwwroot/your_project/static_assets/; }cmdb.wsgi:application是 Django 项目默认生成的 WSGI 入口宝塔的 Python 管理器通常会让你填这个路径不要写错成settings.py。5.2 静态文件 404 的排查顺序部署后页面无样式90% 是collectstatic没有执行或 Nginx 的alias路径末尾少了一个斜杠。还有一种情况是settings.py里没有配置STATIC_ROOT导致collectstatic直接报错。建议在部署前先在本地执行一次python manage.py collectstatic --dry-run它会列出将要复制的文件清单用来验证目录映射是否正确。5.3 给系统加一个资产导出模块在当前基础上快速增加 Excel 导出功能可以在views.py中写一个使用csv模块的导出视图import csv from django.http import HttpResponse def export_assets(request): response HttpResponse(content_typetext/csv) response[Content-Disposition] attachment; filenameassets.csv writer csv.writer(response) writer.writerow([编号, 名称, 分类, 状态]) for asset in Asset.objects.all(): writer.writerow([asset.sn, asset.name, asset.category.name, asset.get_status_display()]) return responsecontent_typetext/csv让浏览器识别为下载文件Content-Disposition里的filename指定下载名。把这函数加入 URL 后就可以在列表页加一个导出按钮点击后直接下载 csv用 Excel 打开不会乱码注意 Windows 下可能需要改成 UTF-8 with BOM。最后提醒一点Asset 模型中用DecimalField存价格导出时asset.price是 Decimal 对象直接写到 csv 会变成字符串不影响正确性但如果你要累加统计务必在视图里做sum(asset.price for asset in qs)而不是在模板里执行计算。本文还有配套的精品资源点击获取