Django+数据可视化的短视频用户兴趣分析系统设计实践
做毕设辅导这几年短视频类的分析系统是我接到过需求量最大的方向之一。很多同学拿到“基于Django数据可视化的短视频用户兴趣分析”这个题目时第一反应是到处找源码第二反应是装了跑不起来第三反应是跑起来了看不懂代码最后答辩被问两句就露馅。这篇就从头到尾把这类项目的设计思路、核心实现和常见坑位一次说清楚。1. 项目定位与整体架构设计1.1 这个毕设到底在做什么短视频用户兴趣分析本质是一个“用户行为画像”类系统。它采集用户在短视频平台上的行为数据比如观看、点赞、评论、转发、完播比例通过这些行为反推用户的兴趣偏好最终用可视化的方式把分析结果呈现出来。这类项目之所以在毕设里特别受欢迎是因为它天然涵盖了完整的Web开发链路后端框架Django、数据库建模MySQL或SQLite、数据采集爬虫脚本或模拟数据、算法模型兴趣权重计算和前端可视化ECharts图表。一个项目就能把大学四年学的核心课程串起来答辩时讲起来也很有层次感。学术上这类系统叫“基于兴趣标签的用户画像系统”工程上叫“短视频用户行为分析平台”本质是同一个东西。市面上的标价从一百到一千都有但源码质量参差不齐很多存在依赖冲突、数据库连接写死、图表数据写死在HTML里等问题拿到手根本没法改。1.2 为什么选Django而不是Flask或SpringBoot选型这个问题很多同学纠结过。短视频兴趣分析本身是有一定数据处理量的但作为毕设规模通常控制在十万到百万级行为记录以内这个量级下Python完全扛得住。我一般推荐Django而不是Flask核心原因是Django自带Admin后台和ORM调试和交付演示都方便得多。Django的ORM让数据查询不用手写SQL这对很多数据库基础薄弱的同学是福音。比如要查“每个兴趣标签的平均点赞数”直接写Interest.objects.values(tag).annotate(avg_scoreAvg(like_count))就行不需要处理原生SQL拼接。Admin后台可以让你在演示时直接增删改查数据后期改数据、调测试样本都很快。Flask虽然更轻量、上手更快但所有模块都要自己搭用户认证、表单验证、ORM都需要额外装扩展。毕设阶段你本来就要花大量时间写文档和做测试用例搭框架的时间越少越好。SpringBoot在Java技术栈里性能确实更强但Java的部署方式对毕设演示不友好你需要配置Maven、打JAR包、装JDK远没有Django一条python manage.py runserver来的直接。1.3 整体技术栈与数据流转路径这个项目的完整技术栈按我当时带A同学做的那个版本给大家参考前端用的是Django模板语言加原生模板图表组件采用ECharts通过Ajax接口获取JSON数据并渲染。交互层面用原生的HTML/CSS/JavaScript不需要额外引入Vue或React。这样做的好处是答辩时无论老师问前端原理还是后端接口你都能讲清楚每个细节不用担心装了构建工具却答不上来“它是怎么工作的”这类问题。后端就是Django 3.x或者4.x版本Python环境3.8左右稳定版就好数据库选用MySQL 8.0实际开发调试阶段也会通过SQLite来快速验证逻辑。数据采集层可能采用爬虫方式收集平台公开数据但数据并非随意公开和允许采集爬虫也存在合规风险我这里更建议的做法是使用公开数据集或者自建模拟数据脚本生成符合真实分布规律的数据这样既能展示技术完整性又不会触及数据红线。数据流向分为四个环节原始行为数据入库清洗转换兴趣权重计算可视化结果渲染。下面用数据表设计来展开说明。2. 核心数据表设计与兴趣模型2.1 短视频用户分析的数据从哪来建表之前先要把数据来源想清楚。别一上来就写爬虫爬虫爬出来的数据脏数据多字段还经常不完整。很多人爬回来的评论里全是表情符号和URL清洗就要花掉好几天时间。我个人的建议是先用模拟数据生成脚本按照真实的数据分布规律生成一批观感自然的测试数据。比如用户ID用UUID生成视频分类均匀分布在“美食、旅行、游戏、学习、健身、美妆、科技、宠物”这八个方向行为数据时间戳分布在最近30天内。生成完直接存入数据库后续整套分析逻辑都用这批数据来跑。这样有几个实际好处可控性好数据量精确可控测试用例能稳定复现字段完整不会出现某个字段大面积为空的情况演示效果好按真实分布生成出来的图表看着自然不会像随机数那样过于混乱。做完整套流程后再考虑要不要写爬虫而且爬虫只爬取页面公开的基础信息不触及非公开内容只把采集到的数据作为存档学习用途。从安全合规和数据完整性的角度考虑模拟数据生成的方案在毕设阶段是稳的。2.2 数据库表的字段设计与关系拆解整个系统的数据模型我拆成四个核心表用户表、视频表、行为记录表、兴趣标签表。下面是关键字段设计参考。第一个是用户表。字段包括用户ID、昵称、头像地址、注册时间、所在城市。用户表本身很简单主要用来做行为数据的维度拆分比如按城市分析用户兴趣差异这个维度在答辩时经常会被问建议保留。第二个是视频表。字段包括视频ID、标题、分类标签、作者、发布时间、播放总量、点赞总量、评论总量、分享总量。视频表承担的是内容维度的属性记录按照视频的所属类别来实现用户兴趣匹配因为用户看什么短视频更加核心的判断依据是视频的归属类别。第三个是行为记录表。这个表是整个系统的核心也是数据量最大的表。字段包括记录ID、用户ID、视频ID、行为类型、行为时间、观看时长。行为类型分为播放、点赞、评论、收藏、分享五种。建议建表时加上联合索引否则数据量到几十万条时按用户查行为记录会很慢。第四个是兴趣标签表。字段包括ID、用户ID、兴趣标签、兴趣得分、更新时间。这张表不是直接存原始行为的而是通过定时任务或者实时计算把用户的行为映射到“美食、旅行、游戏”等标签上再通过评分公式计算得分最终展示到前端图谱里。表之间关系很简单用户表与行为记录表一对多视频表与行为记录表一对多用户表与兴趣标签表一对多。外键字段建好索引多表联查时才不会卡。数据库引擎直接用InnoDB事务处理有保障表结构要带create_time字段后面分组统计时间趋势时要用到。2.3 兴趣得分计算模型用户看什么就算兴趣吗兴趣模型是整个项目最容易做浅的地方很多代码直接就是“用户点赞了美食视频美食标签就加一分”这种一次性计数逻辑。真按这样做得到的结果非常粗糙体现不出分析能力答辩时老师往往抓住这一块追问容易卡壳。我常用的方案是“多行为加权累计评分”模型。核心思路是不同行为反映的兴趣强度不一样。比如一个用户看了美食视频10秒就划走说明兴趣很弱但如果主动搜索了美食内容并评论互动兴趣就很强。我们据此来设计不同行为的权重系数。参考权重配比播放完成得1分、点赞得3分、收藏得5分、评论得4分、分享得6分、完整看完加2分。设定这些权重后进行加权求和计算关键则取决于观看时长与视频总时长的比例关系。如果完播率低于30%就算只计播放行为的1分超过80%则有完播加分。用户对某个标签的兴趣得分 该用户在该标签下所有行为加权分值求和 基于观看时长的完播调整分。得到具体数值后再对所有标签的得分做归一化处理。常用的做法是最大最小值归一化把最终得分映射到0到100的范围前端ECharts直接展示为百分制展示效果会好很多。归一化公式归一化得分 原始得分-最小得分/最大得分-最小得分×100。这样做出来的雷达图才有辨识度不同标签之间能拉开差距而不是所有标签都糊在60分附近的奇怪形状。3. 可视化看板与前端图表实现3.1 这个系统需要展示哪些图表可视化部分的图表逻辑要有设计感不是拼数量而是每一张图标都要回应一个分析问题。我把它拆成六个核心图表模块覆盖六种不同的问题场景总体数据概览回答“平台整体表现怎么样”兴趣标签分布回答“用户群体喜欢什么”行为类型占比回答“用户在平台怎么互动”兴趣随时间趋势回答“用户的兴趣怎么变化”用户活跃时段分析回答“什么时候在线的人多”某标签下用户排行榜回答“哪些用户对该领域贡献最大”。这几个图表不是随意拍的而是层层递进的思路。先看整体再看分布再看趋势再看个体。答辩时老师问你“为什么选这张图”你可以讲清楚这张图回应什么业务问题比笼统地说“展示数据”要强很多。从实现角度来看图表均通过ECharts实现。每个图表由前端Ajax请求后端JSON数据接口前端拿到数组数据后渲染成图。后端视图通过ORM聚合数据库数据将结果转成字典列表再JsonResponse返回给前端。Django自带JsonResponse模块做JSON序列化即可不需要额外装DRFDjango REST Framework。这也控制了一个项目依赖数量在部署环节避免不必要的坑。3.2 图片配色、布局与前端页面结构页面框架容纳六个图表模块可以按照这样一个分隔布局顶部是标题栏和总数据概览卡片这里用Bootstrap栅格系统从上到下依次排列卡片显示视频总量、用户总量、总互动次数、平均完播率四个核心指标中间部分左侧放兴趣标签雷达图右侧放行为类型占比饼图观众交互方式比例分布再往下左侧放置用户活跃时段柱状图右侧放最近30天兴趣趋势折线图页面底部放标签用户排行榜表格。前端页面骨架使用Django的模板继承。一个base.html来放公共代码如侧边导航和引入的CSS/JS文件每个页面继承它。静态文件推荐使用Django的static模板标签这样部署到服务器时改一个STATIC_URL配置所有资源路径也会相应调整不会出现页面样式突然崩掉的现象。配色上要选的克制一点套用现代看板式的配色方案尽量避免那种大红大绿的经典编程教材配色。我通常用蓝色和绿色作为主色系橙色黄色作为强调色。ECharts颜色数组里配上几个十六进制色值就行。背景色用浅灰或者纯白卡片之间留出间距比密密麻麻地挤在一起清爽很多。3.3 ECharts图表的数据接口设计前端和后端的数据交互模式要讲清楚。后端视图写成一个API接口前端通过jQuery发Ajax请求取数据。举个例子行为类型占比饼图的数据接口长这样def behavior_pie_data(request): behaviors BehaviorRecord.objects.values(behavior_type).annotate(countCount(id)) data [{name: BehaviorTypeMap.get(item[behavior_type], 未知), value: item[count]} for item in behaviors] return JsonResponse({code: 0, data: data})前端拿到数据直接塞进ECharts的series里$.get(/api/behavior_pie/, function(res) { if (res.code 0) { pieChart.setOption({ series: [{ type: pie, radius: [40%, 70%], data: res.data }] }); } });这个交互有几个细节值得注意。后端返回的JSON不要直接是图表数据数组要包一层状态码和数据结构比如{code: 0, data: [...]}这样前端统一做错误处理和守卫判断。时间趋势数据是由后端来完成分组聚合而不要让前端拿到全量数据来处理。比如按天统计互动量就得靠Django ORM的TruncDate函数来实现。用户活跃时段分析数据等等就是整点小时数据直接用hour(create_time)进行分组。同时还需要注意JSON序列化时Decimal和date类型可能报错的问题。Django ORM算出的平均值往往是Decimal类型ECharts能正常处理但JSON序列化必须做类型转换。封装一个工具函数把非原生JSON类型统一转成float或str避免接口报错。def json_safe(data): if isinstance(data, Decimal): return float(data) if isinstance(data, datetime): return data.strftime(%Y-%m-%d %H:%M:%S) return data4. 代码讲解方案与项目部署实操4.1 环境准备和项目初始化项目环境准备跟着下面这个顺序执行能规避掉大多数依赖冲突。首先Python版本选3.8到3.10之间的版本有些镜像源和第三方库在高版本下要么缺少预编译包要么编译会报错。创建虚拟环境之后安装依赖包依赖不要手动一个个装用pip install -r requirements.txt整体处理。# requirements.txt django3.2,4.0 mysqlclient2.1.1 pymysql1.0.2 requests2.28.1 pandas1.5.3 numpy1.24.3Django项目用官方命令创建django-admin startproject shortvideo_analysis然后创建一个名叫analysis的应用。如果源码压缩包已经帮你搭好了框架那就省掉创建步骤但依赖安装和环境变量配置仍然要自己过一遍。配置MySQL连接这一步是新手最容易报错的地方。Django默认配置用的SQLite切换数据库时要改settings.py里的DATABASES配置DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: shortvideo_db, USER: root, PASSWORD: 你的密码, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }改成MySQL之后注意在__init__.py里加pymysql.install_as_MySQLdb()否则会报找不到MySQLdb库的错误。这个坑几乎每个用PyMySQL的人都会踩一次。在Windows本地环境建议用SQLite开发最后部署到服务器或演示时再切换到MySQL两种库ORM代码兼容性很好改一下配置就行。4.2 数据迁移、模拟数据生成和管理员配置模型写好后先python manage.py makemigrations再python manage.py migrate把表结构建出来。检查建表是否成功可以直接连进数据库用show tables验证也可以打开Django Admin后台查看。模拟数据生成脚本放在应用的management文件夹下这样可以通过python manage.py generate_data命令生成数据。脚本逻辑不难随机生成500个用户2000个视频每个用户生成50到200条行为记录总数据量大约十万条左右。生成的脚本用faker或者自写随机函数。class Command(BaseCommand): def handle(self, *args, **options): users [UserProfile(usernamef用户{i}, cityrandom.choice(CITIES)) for i in range(500)] UserProfile.objects.bulk_create(users) self.stdout.write(self.style.SUCCESS(用户数据生成成功))用bulk_create批量插入而不是循环单条save()因为500个用户循环创建还能忍但十万条行为记录循环创建会等很久。bulk_create能做到秒级入库即使十万条记录也基本在一两秒内完成。模拟数据随机可以但要有权重倾向。如果每个用户每个标签都均匀分布最后结果图表就会缺乏辨识度。可以给每个用户随机指定1到3个主导兴趣方向这些方向的数据量权重翻倍图表趋势会清晰很多。数据生成后创建管理员账号python manage.py createsuperuser随后可通过Admin后台手动添加、修改、删除数据现场的演示会更灵活。比如有老师问“数据是真的吗”你可以直接说部分是模拟数据部分来自公开数据集预处理后导入但组合符合真实分布特征用来验证分析算法完全够用。4.3 核心代码讲解的关键模块怎么讲代码讲解环节对学生来说往往比较棘手因为很多源码拿到手后并未吃透而老师一旦追问就容易被问住。开讲解时建议按三条主线讲数据流、核心算法、可视化联动。数据流的逻辑核心是数据从哪来、怎么清洗、存到哪张表。要能讲清楚generate_data脚本生成模拟数据的过程以及在公开数据集的使用上哪些字段是直接使用、哪些做了预处理。老师问数据处理相关问题只要把这两个环节描述清楚基本就不是问题。核心算法部分是重点中的重点必须把兴趣得分公式写在纸上讲。拿一个具体的用户案例来算一遍比如某用户在美食标签下有3次播放、1次点赞、1次收藏那么加权得分就是3×1 1×3 1×5 11分。再结合完播率修正和归一化过程分数最终变得直观这个具体的计算展示远比空谈公式有说服力。前端图表理解起来也很清晰ECharts各图标对应哪个接口接口执行了怎样的数据库操作前端拿到数据后怎样渲染讲清这三步链路就讲清了整个项目。4.4 项目部署时要解决的几个细节项目答辩前通常需要部署到演示环境。最省事的做法是让源代码在同一局域网内运行服务器上或自己的电脑上通过局域网IP进行访问。需要把settings.py里的ALLOWED_HOSTS改成[*]否则手机或教室电脑访问会报Bad Request。python manage.py runserver 0.0.0.0:8000启动服务之后记得检查Windows防火墙是否拦截了8000端口。很多时候代码没问题但外部设备访问不了排查一看是防火墙拦了入站连接。本地开发时直接浏览器访问localhost:8000没感觉真到答辩演示时发现手机访问不了就会很被动。提前在答辩前两天进行一次跨设备访问测试比较稳妥。如果服务器上是Linux环境部署建议用gunicorn加Nginx的方式跑但不建议在答辩前临时折腾容易引入新问题。使用Django自带开发服务器作为演示用途是完全没问题的。关键点是DEBUG保持为True静态文件能正常加载runserver监听地址写0.0.0.0非本机访问权限才能打开。这两处改完基本可以保证demo环境稳定。5. 常见问题排查与答辩准备经验5.1 数据库连接异常和迁移报错通信链接失败通常是MySQL服务没有启动或者密码不对。检查任务管理器确认mysqld进程然后命令行测试连接mysql -u root -p。密码不对就重置密码命令行操作也很方便。表结构没有更新多数原因是漏执行了migrate。每次修改模型后都要依次执行makemigrations和migrate。Django的迁移机制差异环境下常出现包版本不一致导致的异常比如一个常见的报错是mysqlclient相关错误。Windows下通常要安装mysqlclient的预编译包或者直接换PyMySQL方案。字段缺失报错基本是数据库迁移顺序问题。小心处理新旧迁移文件如果麻烦出现就直接python manage.py migrate app_name zero重来一遍比到处检索要快得多。5.2 前端图表加载不出来如何排查图表初始化时报Chart is not defined90%是ECharts的JS文件路径引入错误。浏览器F12打开控制台看到红色网络报错就能定位检查base.html里的静态文件路径即可。接口返回的数据格式不对通常表现为前端收到undefined或控制台报Cannot read property length of undefined。这时候先直接用浏览器访问接口地址/api/xxx/看返回JSON如果后端报500错误看Django日志里的Traceback定位问题如果返回的字段名不匹配说明前端取数据的键名写错了需要保持一致。图表渲染出来是空白通常是数据和格式没有问题但直接把响应数据当成series.data喂进去了没有包一层data字段取值。一块块分别逐个检查通常十分钟内能定位到问题。5.3 答辩时老师最爱问的问题怎么回答答辩环节回答得好分数往往比代码本身更关键。老师喜欢从系统架构、算法逻辑、数据来源三个方面提问。其中系统架构方面喜欢问“整个系统的架构是什么前端和后端怎么交互的”回答思路是按照“浏览器发起请求-Django路由分发-视图处理数据-ORM操作数据库-渲染模板返回页面”这条完整链路描述逻辑防止被细节追问时卡壳。算法逻辑方面爱问“兴趣得分是怎么计算的为什么用这个权重”回答思路是把计算公式和权重系数写清楚讲解“点赞权重低于收藏”的业务逻辑因为收藏代表用户愿意再次访问投入的注意度和意愿更强。数据库设计方面爱问“为什么用MySQL、行为数据到百万级怎么办”回答思路是表明MySQL在中小数据量下性能稳定、生态成熟、和Django配合好后续优化方向可以扩展为引入缓存机制或者对行为记录表按时间做分区展示思考深度即可。5.4 文档编排和源码交付的注意事项给源码做交付时文档结构尽量按“项目介绍-技术架构-数据库设计-功能实现-测试用例-部署说明”这个框架来编排每一步和代码对应上。说明文档不要在最后草草写从第一天开发就开始记录每完成一个功能模块就补充一段最后汇总工作量会小很多。代码里要写必要注释但不要写废话。核心算法的函数处加三四行注释说明输入输出和公式思路即可。老师浏览代码时会重点看文件结构、功能组织和注释风格一个结构清晰的代码目录要比堆了一堆乱七八糟的文件要加分得多。文档中建议包含几条核心接口的调用示例以及系统运行最低配置要求。答辩演示时建议提前准备好两台不同设备用笔记本投屏演示时老师手机访问局域网地址查看页面效果会给整体演示增加不少真实感。6. 一条龙定制服务和源码二次开发经验毕设定制这件事从我自己带过多个学生的经验来讲靠谱的交付不光是给一套代码更重要的是在交付之后把能力也交付出去让学生能讲清自己所做项目的来龙去脉。定制服务里最常见的需求是换主题。比如导师要求把“短视频用户兴趣分析”改成“电商用户购买行为分析”核心架构基本不用大改只需要换视频表的字段为商品表字段行为类型换成浏览、加购、购买、收藏兴趣标签换成商品分类雷达图换成商品品类偏好即可。改完主题后图表、接口、模拟数据脚本同步调整工作量大约两到三天收益是项目新颖度显著提升答辩时脱离千篇一律的短视频模板。第二类常见需求是功能扩展增加一个推荐模块。这个适合算法基础较好的同学。实现很简单基于用户兴趣得分向量计算余弦相似度取TopN个相似用户把这些用户高分视频推荐给当前用户。多了一张推荐结果表和一个推荐接口前端加一个“推荐列表”的表格或卡片区即可。加了这个模块就能在答辩时主动讲协同过滤算法项目的技术深度马上上一个台阶。源码拿到手之后建议先花半天时间通读项目结构和关键代码再花半天时间处理环境和部署千万不要拿到代码就直接跑。很多同学运行失败都是因为依赖版本冲突而通读代码的过程能让你在报告中准确地描述每个功能模块对应在哪段代码为写说明文档积累素材。如果是请人做的项目务必自己从头到尾跑一遍模拟数据生成和图表展示的流程熟悉每个按钮、每个图表对应的数据含义。答辩现场最尴尬的场面就是老师问一个图表数据是怎么来的学生支支吾吾说不上来。项目不是交了源码就结束了你真正理解的部分才是最终能呈现出来的水平。最后分享一下我个人带项目时的经验这类系统本身并不难绝大多数同学的问题不是“做不出来”而是“不知道从何下手”和“做完了讲不清楚”。如果你的进度在同一阶段建议先跑通一条最简单的链路“模拟数据入库 → 一个图表展示 → 用Admin后台改数据 → 图表随之更新”。这条链路通顺之后整个系统的骨架就立起来了后续扩展只是添砖加瓦而已。