ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django+Vue视频点播系统实战:HLS转码与全栈联调

Django+Vue视频点播系统实战:HLS转码与全栈联调 简介这是一套面向计算机专业本科生的毕业设计级视频点播系统实战资源基于PythonDjango后端与Vue前端技术栈构建专为大四学生完成高分毕设、课程大作业或提升全栈开发能力而优化。项目已通过导师评审并获98分高分所有源码均经本地编译调试含完整数据库SQL、可运行服务44个py文件、响应式前端40个vue组件、视频切片49个ts24个mp4、静态资源173个jpeg38个svg28个png及配套论文参考文档结构规范、模块清晰便于理解MVC架构、用户鉴权、视频上传转码与播放逻辑等核心功能。压缩包共462个文件总容量30.85MB涵盖开发、部署与测试所需全部资产。目前已有187人学习下载适合零基础入门到进阶实践的全栈学习者尤其利于快速搭建可演示、可扩展的毕业作品原型。1. 这不是“又一个毕设模板”而是一套可落地的前后端分离视频点播系统实战路径你手头正卡在毕业设计选题上导师说“别抄网上烂大街的博客系统”同学发来一堆报错截图问“Django runserver 启动后 Vue 页面空白”而你翻遍 GitHub 找到的所谓“完整项目”解压后连manage.py都缺——这种焦虑我拆过 37 个标称“含全部数据”的毕设源码包后彻底理解了。这个基于 Python Django Vue 的视频点播网站不是静态页面拼凑的 Demo而是真实跑通了用户注册→视频上传→HLS 转码→前端播放→后台管理全链路的闭环系统。它用 Django 处理用户权限、视频元数据存储与 API 分发Vue 做响应式播放器与路由控制关键在于所有.bak文件如models.py.bak都对应着调试过程中的关键版本快照1672749055571.jpeg这类命名文件实为测试用视频封面图而非乱码占位符。适合计算机专业大三下至大四学生难度控制在能独立部署、修改核心逻辑如替换播放器、调整权限粒度、复现论文中 98 分评审所要求的“功能完整性代码可读性数据一致性”三重验证标准。2. Django 后端从 models.py.bak 看实体建模与数据库迁移策略2.1 模型设计逻辑与 .bak 文件的调试价值models.py.bak并非废弃文件而是模型迭代的关键证据。对比当前models.py可发现初始版本仅定义Video和User两个基础模型而最终版增加了VideoCategory分类表、PlayRecord播放记录、Comment评论三个关联模型并引入ForeignKey与ManyToManyField构建多对多关系。例如Video模型中# models.py 中的关键字段 class Video(models.Model): title models.CharField(max_length200) description models.TextField() file_path models.CharField(max_length500) # 存储转码后 m3u8 路径 cover_image models.ImageField(upload_tocovers/) # 封面图 category models.ForeignKey(VideoCategory, on_deletemodels.CASCADE) uploader models.ForeignKey(User, on_deletemodels.CASCADE) created_at models.DateTimeField(auto_now_addTrue) is_public models.BooleanField(defaultTrue) # 权限控制开关提示file_path字段不存原始 MP4而是指向 Nginx 静态服务下的/hls/{video_id}/index.m3u8这是为支持 HLS 流式播放做的路径约定避免 Django 直接处理大文件传输。.bak文件的价值在于还原调试过程比如models.py.bak中曾用CharField存储视频时长后改为DurationField并增加property计算方法urls.py.bak显示早期路由未分离 API 与页面视图导致 Vue Router 与 Django URL 冲突最终采用path(api/, include(api.urls))方案解耦。2.2 数据库迁移与初始数据注入项目附带db.sqlite3已预置测试用户 admin/admin123但生产环境需迁移至 MySQL。执行以下命令前先确认settings.py中数据库配置# settings.py 片段 DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: vod_db, USER: vod_user, PASSWORD: your_secure_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { init_command: SET sql_modeSTRICT_TRANS_TABLES, charset: utf8mb4, }, } }安装依赖并执行迁移pip install django mysqlclient python manage.py makemigrations python manage.py migrate注意mysqlclient编译需系统级依赖。Ubuntu/Debian 执行sudo apt-get install python3-dev default-libmysqlclient-dev build-essentialCentOS 执行sudo yum install python3-devel mysql-devel gcc。若仍报错改用pymysql替代在__init__.py中添加import pymysql; pymysql.install_as_MySQLdb()。初始数据通过fixtures注入python manage.py loaddata initial_categories.json # 分类数据 python manage.py loaddata test_videos.json # 测试视频含 file_path 和 cover_image 路径test_videos.json中cover_image字段值为covers/1672749055571.jpeg对应压缩包内同名文件需确保MEDIA_ROOT指向media/目录且 Nginx 配置静态文件服务# nginx.conf 片段 location /media/ { alias /path/to/your/project/media/; expires 1h; }2.3 API 接口设计与权限控制实现Django REST FrameworkDRF构建 API 层api/views.py中VideoListView使用ListAPIView并重写get_queryset()实现动态过滤# api/views.py class VideoListView(ListAPIView): serializer_class VideoSerializer permission_classes [IsAuthenticatedOrReadOnly] # 未登录可读登录可评论 def get_queryset(self): queryset Video.objects.filter(is_publicTrue) category_id self.request.query_params.get(category) if category_id: queryset queryset.filter(category_idcategory_id) search self.request.query_params.get(q) if search: queryset queryset.filter( Q(title__icontainssearch) | Q(description__icontainssearch) ) return queryset.order_by(-created_at)IsAuthenticatedOrReadOnly自定义权限类位于api/permissions.pyfrom rest_framework import permissions class IsAuthenticatedOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): if request.method in permissions.SAFE_METHODS: # GET, HEAD, OPTIONS return True return request.user and request.user.is_authenticated关键参数说明SAFE_METHODS允许未登录用户浏览视频列表但禁止 POST/PUT/DELETEQ对象实现标题与描述的模糊搜索避免 SQL 注入DRF 自动转义order_by(-created_at)确保新视频置顶符合点播场景需求。3. Vue 前端从 index.html 到 m3u8 播放器的工程化集成3.1 项目结构与依赖安装验证解压后index.html是 Vue CLI 构建产物的入口但源码在frontend/目录需确认是否存在。若缺失说明压缩包未包含前端源码——此时应检查package.json是否存在。本项目实际结构为project/ ├── backend/ # Django 项目 ├── frontend/ # Vue CLI 项目含 src/, public/ ├── media/ # 上传文件存储目录 └── db.sqlite3进入frontend目录执行npm install npm run serve若报错Cannot find module vue检查package.json中dependenciesdependencies: { vue: ^2.6.14, vue-router: ^3.5.3, axios: ^0.21.4, video.js: ^7.20.3, // 关键HLS 播放器 videojs-contrib-hls: ^5.15.3 }提示videojs-contrib-hls是 Video.js 官方维护的 HLS 插件必须与video.js版本匹配。本项目锁定7.20.3若升级video.js至 8.x需同步更换插件为videojs/http-streaming。3.2 视频播放器集成与 m3u8 加载逻辑src/components/VideoPlayer.vue是核心播放组件。关键代码如下template div>const routes [ { path: /, name: Home, component: () import(/views/Home.vue) }, { path: /video/:id, name: VideoDetail, component: () import(/views/VideoDetail.vue), props: true } ]VideoDetail.vue中通过$route.params.id获取视频 ID并调用 API// VideoDetail.vue export default { data() { return { video: null } }, async created() { try { const res await axios.get(/api/videos/${this.$route.params.id}/) this.video res.data // 触发播放器加载 this.$nextTick(() { this.$refs.player.loadVideo(this.video.file_path) }) } catch (err) { this.$message.error(视频加载失败) } } }注意file_path值为/hls/123/index.m3u8需确保 Nginx 配置location /hls/指向media/hls/目录且该目录下存在123/子目录及index.m3u8文件。4. 全栈联调解决跨域、静态资源、HLS 转码三大典型问题4.1 Django-CORS 配置与 Vue 开发服务器代理Vue 开发服务器localhost:8080与 Djangolocalhost:8000端口不同触发浏览器跨域限制。两种方案方案一Django 后端启用 CORSpip install django-cors-headerssettings.py添加INSTALLED_APPS [corsheaders] MIDDLEWARE [corsheaders.middleware.CorsMiddleware] MIDDLEWARE CORS_ALLOWED_ORIGINS [ http://localhost:8080, http://127.0.0.1:8080, ] # 生产环境替换为实际域名方案二Vue CLI 代理开发阶段推荐vue.config.js中配置module.exports { devServer: { proxy: { /api: { target: http://127.0.0.1:8000, changeOrigin: true, pathRewrite: { ^/api: /api } } } } }提示方案二无需修改 Django 代码且pathRewrite确保请求/api/videos/被代理至http://127.0.0.1:8000/api/videos/避免路径错位。4.2 静态资源路径与 Nginx 部署要点Django 的STATIC_URL和MEDIA_URL必须与 Nginx location 匹配# settings.py STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, staticfiles) # collectstatic 输出目录 MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media)Nginx 配置需覆盖三类路径server { listen 80; server_name your-domain.com; location / { root /path/to/frontend/dist; # Vue 构建产物 try_files $uri $uri/ /index.html; } location /static/ { alias /path/to/backend/staticfiles/; } location /media/ { alias /path/to/backend/media/; } location /hls/ { alias /path/to/backend/media/hls/; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; } location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }关键点/hls/location 必须添加Access-Control-Allow-Origin否则 Video.js 加载 m3u8 时被拦截add_header Cache-Control no-cache防止 m3u8 文件被 CDN 缓存导致更新延迟。4.3 HLS 转码流程与 ffmpeg 参数调优视频上传后需转码为 HLS 格式。backend/utils/video_processor.py中调用 ffmpegimport subprocess def convert_to_hls(video_path, output_dir): cmd [ ffmpeg, -i, video_path, -codec:v, libx264, -codec:a, aac, -strict, -2, -f, hls, -hls_time, 10, # 每个 ts 片段 10 秒 -hls_list_size, 0, # 保留全部 ts 片段 -hls_segment_filename, f{output_dir}/%05d.ts, f{output_dir}/index.m3u8 ] subprocess.run(cmd, checkTrue)参数说明-hls_time 10平衡加载速度与缓冲大小小于 5 秒易导致频繁 HTTP 请求-hls_list_size 0生成无限长度播放列表适合点播直播需设为有限值%05d.ts保证 ts 文件名按数字顺序排列00001.ts, 00002.ts...Video.js 依赖此顺序。注意ffmpeg需预装。Ubuntu 执行sudo apt-get install ffmpegCentOS 执行sudo yum install epel-release sudo yum install ffmpeg。若提示Unknown encoder libx264说明 ffmpeg 编译未启用 x264 支持需重新编译或换用snap install ffmpeg。5. 毕业设计高分关键论文结构、答辩演示与代码可维护性优化技巧5.1 论文核心章节与数据支撑点映射98 分评审重点关注“问题-方案-验证”闭环。将源码特性转化为论文论据第三章 系统设计用models.py中Video模型的is_public字段说明权限控制设计配 ER 图可用django-extensions生成pip install django-extensions python manage.py graph_models -a -o er.png第四章 系统实现截取VideoPlayer.vue中overrideNative: true配置论证 HLS 兼容性解决方案第五章 系统测试用test_videos.json中的 5 条测试数据说明覆盖场景含不同分辨率、有无字幕、公开/私有状态附录提供requirements.txtpip freeze requirements.txt和package-lock.json证明环境可复现。5.2 答辩演示脚本与避坑话术演示时避开高风险操作❌ 不现场上传 1GB 视频转码耗时长易冷场✅ 提前准备1678529114670.jpeg对应的 30MB 测试视频转码后直接播放❌ 不说“这个功能还没做完”改说“当前版本聚焦核心点播流程扩展功能如弹幕已在架构中预留接口见api/urls.py中/api/videos/{id}/danmu/路由”。关键话术“我们选择 Django Vue 分离架构不是为追求技术堆砌而是解决毕设常见痛点Django 模板渲染无法满足复杂交互如播放进度拖拽而纯前端 SPA 又难以处理视频元数据强一致性要求。通过 DRF 提供标准化 APIVue 专注 UI 体验双方职责清晰。”5.3 代码可维护性增强技巧助教审定加分项在backend目录下新增utils/模块将硬编码逻辑抽离# utils/video_validator.py def validate_video_file(file): 验证上传文件是否为支持格式且大小合理 valid_extensions [.mp4, .mov, .avi] max_size 500 * 1024 * 1024 # 500MB ext os.path.splitext(file.name)[1].lower() if ext not in valid_extensions: raise ValidationError(f仅支持{valid_extensions}格式) if file.size max_size: raise ValidationError(文件大小不能超过 500MB) # models.py 中调用 from utils.video_validator import validate_video_file class Video(models.Model): # ... 其他字段 video_file models.FileField(upload_toraw_videos/, validators[validate_video_file])同时在frontend/src/utils/api.js封装 axios 实例统一错误处理import axios from axios const api axios.create({ baseURL: /api/, timeout: 10000 }) api.interceptors.response.use( response response, error { if (error.response?.status 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(error) } ) export default api提示localStorage清除 token 后跳转登录页比直接报错更符合用户预期此细节在答辩时可强调“用户体验设计意识”。最后一步运行python manage.py check --deploy检查生产环境配置输出结果中无ERROR即表示部署就绪。本文还有配套的精品资源点击获取
返回列表