ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Django毕设实战:Bilibili青少年模式数据分析系统设计与实现

2026/9/29 16:56:12 拓冰建站 浏览量
Django毕设实战:Bilibili青少年模式数据分析系统设计与实现 毕业设计这潭水真的是每年都有人趟出不一样的坑。你手上要是正好拿到“基于django的Bilibili青少年模式使用情况的数据分析系统”这个题目第一眼估计和我当年一样标题开头写的是“Java计算机毕设”结果后面技术栈却写着Django这到底是让人用Java还是用Python别慌这种“看起来矛盾”的题目在高校毕设里反而是最常见的一种因为题目库是很多年前统一定的写“Java”只是沿用老的命名习惯真正落地的时候你用什么B/S技术栈答辩老师通常更看重“系统能不能跑、逻辑清不清楚、论文顶不顶得住”。这个题目的完整形态其实很清晰一个带用户端和管理后台的Web系统外加一套围绕“青少年模式”的行为数据采集、指标分析和可视化看板最后再配一本看起来像那么回事的说明文档和论文。适合谁做正在选题或者已经拿到类似题目的本科生以及想快速搞懂DjangoBootstrapECharts怎么串成一套完整毕设的人。下面我把整个系统的设计思路、核心代码、常见坑和答辩要点按我自己实际做项目的路子完整过一遍。1. 需求拆解与方案选型1.1 标题里的“Java和Django混搭”怎么理解先说最劝退人的一点题目是“Java计算机毕设”实现却是Django。我接触过的很多毕设题目其实都是这么个情况学校下发题目的时候要么是抄的前几年题目模板要么是“Java”已经变成了“Web项目”的统称。真正做的时候你完全可以用Python的Django来完成这个系统因为题目核心研究对象是“青少年模式使用情况的数据分析”这句话的落点明显偏数据分析和可视化而Python生态在这个赛道上比Java顺手太多。你要是答辩时被老师逮住问“题目不是Java吗你怎么用Python”答案也很现成Django是基于Python的Web框架本质上和Spring Boot一样是解决B/S架构问题的系统层面对外呈现的是Web页面和接口用户并不感知底层是什么语言而且分析模块用Python的pandas、numpy做数据处理比在Java里逐个字段写统计逻辑要快得多。说白了毕设考的是工程思维和分析逻辑不是编程语言信仰。拒绝Java的另一个现实原因是时间。毕设周期一般也就一个学期还要扣除实习、考研、写论文和改格式的时间真正能稳定写代码的时间不到四周。Java那套SSM或Spring Boot光配置环境、写XML、打包部署就能吃掉一个周末Django则是“pip安装startapp”三分钟起项目自带Admin后台还解决了一大半后台管理需求这对毕设来说就是救命稻草。1.2 功能模块划分与业务闭环把题目拆开你会发现这个系统要盘的不是“B站”本身而是“青少年模式”。B站的青少年模式是产品的一个功能开关开启后只展示适合未成年人的内容、限制使用时长那么“使用情况的数据分析”自然就落在了这几个维度上谁开了青少年模式、什么时候开什么时候关、开了之后在看什么东西、每天/每周累计用多长时间、系统拦截了多少不适合的内容请求。由此系统业务自然就分成四个模块用户与权限模块注册登录、角色区分普通用户、管理员、青少年模式开关状态维护。内容管理模块模拟B站视频的标题、分区、标签以及对每个视频做“是否适合青少年观看”的审核标记这是青少年模式过滤的核心依据。行为采集模块记录用户每次播放、暂停、切换、被拦截的行为日志以及青少年模式的每一次开启和关闭记录这些日志就是分析的原料。数据分析与可视化模块围绕行为日志计算开启率、时段热力、内容偏好、平均使用时长、内容拦截率等指标并用ECharts渲染成图表展示到前台。这四个模块串起来就是一个完整的闭环用户在页面上触发行为后端记录日志管理端维护内容分级统计分析模块从日志里汇总指标最后把结果以图表形式反馈出来。整个系统的灵魂在第四块前面三块本质上是为它服务的“数据生产车间”。1.3 Django与Java B/S方案的可比性参考既然题目标题里有Java那干脆把两边的方案放在一起做个对照方便你决定怎么落笔写开题报告里的“技术选型”章节。对比维度Spring Boot / SSMDjango环境搭建Maven/Gradle依赖管理起步配置文件多pip安装startproject一条命令内置开发服务器后台管理需要自己写增删改查页面Admin站点自动生成几分钟出一个管理后台ORM与数据库迁移MyBatis写SQL或JPA写实体类Django ORM migrate迁移改模型跑一次命令就同步数据分析生态手动遍历List写统计Excel导出要引POIORM聚合一行代码出结果pandas/Numpy随时接上部署复杂度打包war/jar配Tomcatpython manage.py runserver就能演示上线用gunicorn也简单毕设工作量中等偏重很多时间花在配置和冗余代码上轻很多能把省下的时间砸在分析逻辑和论文上这张表不是要踩Java抬Python而是说在这个具体题目里Django能把“数据采集-落库-聚合分析-可视化”的链路明显拉短而这恰恰是评审最关注的地方。如果你不想用Python坚持用Spring Boot做完全能行但你要做好用Java重写聚合统计、还要自己撸一个后台UI的心理准备时间上会紧很多。2. 数据模型与核心功能实现2.1 五张核心表的设计与字段落地数据分析系统最怕的就是建模草率后面写统计SQL时各种别扭。我这个项目里一共设计了五张核心表基本都是围绕“用户-内容-行为”三件事转的。表名核心字段作用UserAccountusername, password_hash, role, is_teen_mode, created_at用户身份和青少年模式状态VideoInfotitle, category, tags, is_teen_safe, play_count, video_url, cover_url模拟B站视频库is_teen_safe是内容分级标记UserBehaviorLoguser_id, video_id, behavior_type, start_time, end_time, duration_seconds, is_teen_mode_on播放、暂停、切换、被拦截等行为流水TeenModeRecorduser_id, action, action_time, duration_minutes每次开启/关闭青少年模式的记录ContentAuditLogvideo_id, audit_result, audit_reason, auditor_id, audit_time管理员对视频做审核标记的留痕UserName表里的is_teen_mode字段是冗余状态真正的分析依据是TeenModeRecord里的流水这样好处是展示当前状态时直接读字段算“开启时长”“退出频率”时去流水表里聚合互不干扰。VideoInfo表里的is_teen_safe是青少年模式过滤的第一层依据ContentAuditLog记录的是审核动作本身方便后面算“审核覆盖率”和“拦截率”。有一个我实际踩过的细节UserBehaviorLog的behavior_type不要用字符串随意填最好用常量枚举play、pause、switch、blocked四种。尤其是“blocked”这一条代表青少年模式下用户试图访问不适合的内容且被系统拦截后面算“拦截率”全靠它你要是漏记这个行为整个分析模块就少了一个关键指标。2.2 Django工程搭建与基础配置要点这个环节本来很机械但总有人卡住我把脚手架步骤列一下。首先创建项目和应用pip install django djangorestframework django-cors-headers channels django-admin startproject teen_project cd teen_project python manage.py startapp user_app python manage.py startapp video_app python manage.py startapp behavior_app python manage.py startapp analysis_app四个app分别对应四个模块比全部写在一个app里强百倍。然后到settings.py里重点处理三件事。第一INSTALLED_APPS里把rest_framework、corsheaders和四个app注册进去第二时区一定要这样配LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ True这个时区配置坑了我一下午后面调试部分我会专门讲。第三做前后端分离时把跨域的配置加上INSTALLED_APPS [corsheaders] MIDDLEWARE.insert(0, corsheaders.middleware.CorsMiddleware) CORS_ALLOW_CREDENTIALS True CORS_ALLOWED_ORIGINS [http://localhost:5173, http://127.0.0.1:8000]初始化数据库就靠migrate一条命令Django的数据表变化全部走makemigrations这一步跑顺了后面改字段就不用慌。2.3 青少年模式的核心逻辑落库青少年模式不是简单一个布尔开关它要能回答“用户什么时候处于受限状态”。我这里的做法是把“开启/关闭”动作本身写入TeenModeRecord同时维护UserAccount.is_teen_mode作为当前状态的快速读取。开启和关闭动作写一个视图函数就能处理from django.db import transaction from django.utils import timezone from teen_project.utils import get_now transaction.atomic def set_teen_mode(request, action): user request.user now timezone.now() if action enable and not user.is_teen_mode: user.is_teen_mode True user.save() TeenModeRecord.objects.create(useruser, actionenable, action_timenow) elif action disable and user.is_teen_mode: # 把本次开启的连续时长算出来再写入 last_enable TeenModeRecord.objects.filter(useruser, actionenable).last() if last_enable: duration_minutes round((now - last_enable.action_time).total_seconds() / 60, 2) TeenModeRecord.objects.filter(idlast_enable.id).update(duration_minutesduration_minutes) user.is_teen_mode False user.save() TeenModeRecord.objects.create(useruser, actiondisable, action_timenow) return JsonResponse({status: ok})关键在disable分支里关闭时要回填上一次开启的持续时长这样后面的“平均单次开启时长”指标才有数据来源。用transaction.atomic包住是为了避免“状态改了但流水没记”或反过来保证数据一致性。内容拦截逻辑也很直白用户请求播放视频时先判断是否处于青少年模式是的话再查VideoInfo.is_teen_safe字段为False就拒绝播放并写一条behavior_typeblocked的日志。数据一致性问答里如果被问到“高并发下你怎么保证日志不丢”我的回答就是“事务包裹一次写入一条完整流水”老师基本认可。2.4 登录态与Token设置Cookie怎么放毕设系统一般不存在高并发但不代表登录态可以随便写。前后端分离时比较省心的方案是DRF SimpleJWT接口返回access_token和refresh_token。但要说到Cookie设置有几点特别容易翻车。第一token放哪儿。直接用localStorage存是最省事的但一旦站点被人注了XSS脚本token就直接被读走。稳妥做法是放到HttpOnly的Cookie里这样JS读不到靠浏览器自动附带。设置Cookie时的参数要带上response JsonResponse({status: ok}) response.set_cookie( access_token, token, max_age24 * 3600, httponlyTrue, samesiteLax, )第二samesite属性要注意。前后端如果不在同一个域浏览器可能默认拦掉跨站的Cookie携带你需要显式设Lax或者None并配合安全条件。调试时如果发现前端每次刷新后登录态就丢了八成就是samesite或domain配的不对。第三Django自带的session认证在纯前后端分离场景下不太好用因为DRF的token认证默认不读Cookie需要自己扩展认证类。我实际是写了一个Authentication类从request.COOKIES里拿access_token然后去SimpleJWT校验二十几行代码搞定比套复杂的OAuth流程舒服得多。3. 数据分析链路与可视化3.1 行为数据从哪里来合规路径要先想清楚做数据分析最尴尬的一步就是“没数据”。不少人一上来就想着爬B站真实数据结果反爬、风控、登录限制折腾了两周数据没爬到几条账号倒先受限了。对于一个毕设来说最稳的路径是自产数据管理端能在后台添加模拟视频并标注is_teen_safe用户端就能在浏览器里正常播放、切换、触发拦截这种行为流水每点一下都会真实落入UserBehaviorLog。拿着这套自产数据指标链路可以完整跑通。如果你想让数据规模显得更大可以再加一个“批量导入”功能管理端支持上传CSV或者JSON格式的模拟行为记录在论文测试部分交代一句“为了验证统计模块在数据量较大时的表现导入了一万条测试数据”这比真实爬取安全且有说服力。答辩被问到“为什么不用真实B站数据”时标准回应是B站没有开放官方数据接口自行抓取获取平台内容存在合规风险因此本项目采用用户操作采集和模拟数据结合的方式验证分析指标的准确性如需真实数据需通过官方合作或授权途径获取。这个回答既专业又滴水不漏。3.2 定义“使用情况”的五个核心指标口径数据分析系统的价值全在指标定义上指标口径不写清楚后面图表画得再炫都没有意义。我这套系统里坚持只做五个核心指标不多不少青少年模式开启率开启过青少年模式的用户数 / 全部注册用户数反映功能触达比例。平均单次开启时长TeenModeRecord里所有enable记录匹配到的duration_minutes之和 / enable记录条数反映一次开启后能坚持多久。日/周活跃使用时长UserBehaviorLog里behavior_type为play的duration_seconds按天或按周汇总后除以对应人数反映整体使用强度。时段使用热力把play行为的开始时间按小时分组统计次数主要看下午放学后和晚上两个高峰。内容拦截率blocked行为次数 /play行为次数 blocked行为次数反映内容分级策略的拦截强度。这五个指标恰好对应论文里的“需求指标”和“性能指标”两块答辩时你把这套口径讲清楚老师会认为你是真的理解了这个数据分析系统要做什么而不是只会把图表无脑堆到一起。3.3 用Django ORM一条条把指标算出来指标明确了后端实现就变成了一道道SQL/ORM题。先说时段热力Django一个TruncHour就能搞定from django.db.models.functions import TruncHour from django.db.models import Count hourly_data ( UserBehaviorLog.objects .filter(behavior_typeplay) .annotate(hourTruncHour(start_time)) .values(hour) .annotate(totalCount(id)) .order_by(hour) )返回结果里hour字段可能是带时区的datetime对象转成“14:00”这种字符串需要再做一步格式化。这里有一个我踩过的坑如果你的start_time是DateTimeField且开启了USE_TZTruncHour切出来的hour会基于UTC而不是本地时间很可能你下午两点的热度被算到了早上六点。解决办法有两种要么查询之前用timezone.localtime把每个时间字段转好再计算要么干脆让start_time改用DateField存日期、另外加一个hour字段存小时数学乖之后我就用第二种绕开时区烦恼。接下来是“内容偏好TOP榜”也就是青少年模式下大家最喜欢把时间花在哪个分区from django.db.models import Sum, F pref_result ( UserBehaviorLog.objects .filter(is_teen_mode_onTrue) .values(video__category) .annotate(total_secondsSum(duration_seconds)) .order_by(-total_seconds)[:10] )这里用到了video__category跨表查询前提是UserBehaviorLog里的video字段是外键。要是你发现total_seconds数值翻倍或者统计不准多半是join后数据重复了可以用.annotate(Sum(duration_seconds, distinctTrue))处理或者干脆把video的category冗余一个字段到行为表里分析起来更快。我在项目里选择了冗余方案冗余字段让统计分析少了很多join性能也更好。3.4 ECharts渲染看板与WebSocket推送可视化层我选ECharts而不是Chart.js主要是ECharts对折线图、饼图、热力图的支持成熟而且中文文档多答辩演示时就算现场改配置也不慌。后端把ORM结果序列化成JSON后前端通过fetch拉取接口数据再渲染。一个示例接口长这样def analyze_overview(request): if request.method ! GET: return JsonResponse({error: method not allowed}, status405) enable_count TeenModeRecord.objects.filter(actionenable).values(user).distinct().count() total_users UserAccount.objects.exclude(roleadmin).count() play_seconds UserBehaviorLog.objects.filter(behavior_typeplay).aggregate(totalSum(duration_seconds)) return JsonResponse({ open_rate: round(enable_count / total_users * 100, 2) if total_users else 0, total_play_seconds: play_seconds[total] or 0, })前端ECharts初始化时先是空数据拿到接口结果后再setOption这个模式网上到处都是不再赘述。至于WebSocket毕设里这属于加分项一般不会强制要求。但你要是想让页面实时刷新“最新一条行为日志”或者“拦截数实时变化”可以用Django Channels。先安装channels和channels-redis项目结构里加一个asgi.pyimport os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from behavior_app.consumers import BehaviorConsumer os.environ.setdefault(DJANGO_SETTINGS_MODULE, teen_project.settings) application ProtocolTypeRouter({ http: get_asgi_application(), websocket: URLRouter([ path(ws/behavior/, BehaviorConsumer.as_asgi()), ]), })consumer里逻辑很简单收到前端发来的任意消息就把数据库里最新一条行为记录推给前端。前端那边用原生WebSocket对象连接onmessage里做图表增量更新。这里务必注意Django Channels要求你部署时用支持ASGI的服务器不能再开python manage.py runserver就当完了如果你不想折腾完全可以用setInterval每三秒轮询一次接口毕设演示效果差别不大。4. 论文组织、调试排查与答辩准备4.1 论文结构怎么和代码一一对应论文不是代码的说明书而是“设计论证”。我的建议是直接按这套结构来绪论写背景和意义落点放在“未成年人网络保护的现实需要”和“内容推荐与内容分级的关系”上顺带提一下国内外短视频平台青少年模式的发展。相关技术介绍Python/Django、MySQL、Bootstrap、ECharts每个技术写清楚“为什么在本项目中用它”。需求分析把系统拆成用户端、管理端、数据分析端三个角色每个角色列出用例画用例图。系统设计总体架构图、数据库E-R图加上上面的五张表字段说明、接口设计列表。系统实现按我前面讲的四层结构逐个模块贴关键代码并配运行截图。系统测试功能测试与性能测试功能测试要包含正常、异常和边界三种用例。关键是系统实现那一章代码不要整段贴只截最核心的三四段比如青少年模式开关逻辑、ORM聚合统计、ECharts渲染其他功能用文字描述即可。老师和查重系统都不会喜欢满屏代码的论文。4.2 调试现场常见问题速查表这部分是从真实开发里踩坑踩出来的每一行都对应一个深夜。直接给你做成速查表。问题现象根本原因解决办法数据库存的时间比本地多了8小时USE_TZTrueTIME_ZONE设置缺失或不对settings里TIME_ZONEAsia/Shanghai写完重启服务后台列表里中文全是乱码MySQL默认字符集不是utf8mb4建库时指定utf8mb4或統一用SQLite避免这个麻烦用户登录后刷新页面就掉线Cookie的samesite属性限制了跨站携带前后端同域部署或samesiteNone加Secure统计播放时长时数字翻倍join后行为记录重复用distinctTrue或把category冗余到行为表删除主表记录时子表残留外键没有设置on_delete级联models.ForeignKey(..., on_deletemodels.CASCADE)前端从接口拿到数据后图表空白后端返回的字段名和前端对不上先看Network面板里实际JSON结构逐字段核对调用.objects.filter().delete()后信号没触发queryset.delete()是批量删除不走save/delete方法需要信号就逐条delete或程序里手动补逻辑这里面最隐蔽的是第1条时区问题不解决你的时段热力分析基本是废的凌晨三点的高峰能给你画到下午去直接毁掉整个分析结果的说服力。我当时排查出来后在论文测试章节还专门补了一段“时区正确性验证”反而变成了一个亮点。4.3 答辩前必须准备好的五个问题答辩其实是一场预判。老师翻来覆去问的就那么几个问题你提前组织好语言现场就不会慌。第一个问题题目写Java你为什么用Python/Django标准回答系统本质是B/S架构Django作为Web框架完成数据采集、业务逻辑和接口发布与题目要求的“Java计算机毕设”在工程目标上一致而且Python的数据处理生态更适合本系统的数据分析模块如果必须使用Java可以用Spring Boot复刻全部功能但开发周期会明显拉长。第二个问题这些数据是真的B站数据吗标准回答真实B站未开放官方数据接口本系统通过用户操作采集和模拟数据导入两种方式产生行为数据重点验证的是数据分析方法和指标模型并预留了对接真实数据的接口后续可结合授权合作方式扩展。第三个问题青少年模式怎么判定一个内容适不适合青少年标准回答系统对每个视频维护is_teen_safe审核标记管理员通过后台审核并写入ContentAuditLog用户在青少年模式下发出播放请求时系统根据该标记做实时拦截并记录blocked日志同时统计审核覆盖率形成“标记-拦截-复盘”的闭环。第四个问题统计模块如果数据量很大性能怎么办标准回答当前采用Django ORM聚合加索引优化的方式行为日志表对user_id和start_time建立复合索引数据规模达到百万级时可引入离线分析和缓存机制比如用pandas做批处理、把指标结果缓存到Redis保证页面秒开。第五个问题你有没有考虑用户隐私标准回答系统对行为记录采用匿名化处理UserAccount只保留必要的登录字段和状态标记不采集真实姓名、家庭位置等敏感信息行为数据仅用于模式统计分析。这个回答既能体现工程素养又能让答辩老师觉得你考虑问题全面。写在后面的一些实在话做一个毕设和开发一个真实商业项目最大的区别在于毕设的重点是“完整闭环”而商业项目更重“极端稳定”。所以我不建议你在毕设里堆微服务、上K8s、搞一大堆炫技却跟题目无关的技术因为答辩老师看的是你能不能把一条业务链路讲通再顺手讲清楚这个系统解决了什么问题。我个人的体会是拿到这种带“数据分析”字眼的题目后最值得投入精力的地方永远是那五个核心指标的口径定义和可视化呈现而不是把时间耗在界面美化或者纠结某个动画效果上。把这个主分析页面做成整个系统的门面让老师打开首页就能看到图表和关键数字你的答辩就已经赢了一半。顺带再留个后手就是WebSocket那条“实时推送最新拦截记录”的效果每次演示时我都能看到评委多看了两眼屏幕这个细节投入小、收益高强烈建议你也保留。