Django+Vue打造视频点播网站:从设计到部署全流程解析
简介:这是一份基于Python与Django、Vue构建的视频点播平台毕业设计项目,面向需要完成全栈课设或学习主流视频点播架构的开发者。资源包共462个文件,以Python源码、Vue组件、图片素材和视频为主,包含44个py文件、40个vue组件、超200张jpeg/png/svg图片素材、24个mp4及49个ts视频分片,另含SQL数据库脚本和docx说明文档,压缩包约30.84MB。项目涵盖用户认证、视频分类展示、搜索、播放器集成与后台管理等功能,解压后还包含源代码备份文件,目录按前端Vue与后端Django分开组织,便于对比调试和二次开发。目前已有93人学习下载,适合作为毕业设计参考和实战项目蓝本,整体是一份完整可运行的视频点播系统资源。 视频点播网站的毕业设计,我见过太多人一上来就抱着“功能越多越好”的心态,结果最后卡在播放器、跨域、大文件上传这几个坑里出不来。如果用 Python + Django 做后端、Vue 做前端来搭一个点播平台,这条技术路线本身非常成熟,也足够撑起一个完整的毕设项目——关键是你得先把“点播”这两个字想清楚,再把核心链路走通。
这篇文章我会按我实际做项目的思路,从整体设计、数据库建模、后端 API、前端播放器接入,到最后的常见问题排查,完整拆一遍。文章里给的方案不一定是唯一的,但都是我验证过、能稳定跑通的路线。无论你是刚开始接触 Django 和 Vue,还是已经有基础想找个完整的项目练手,这篇都能作为一份可落地的参考。
1. 项目整体设计与技术选型
1.1 为什么选 Django + Vue 前后端分离
先说结论: 这个组合是毕设性价比最高的方案之一。
Django 自带 Admin 后台、ORM、用户认证体系,这意味着你不需要从零去写登录、注册、用户表,框架已经帮你把这些基础设施搭好了。你只需要关注业务本身:视频资源管理、分类、评论、播放记录。这对时间有限的毕设来说,能省下将近三分之一的工作量。
Vue 的价值在于前端交互。视频点播网站的核心体验是播放页、视频列表、筛选分类,这些用 Vue 组件化开发会非常清晰。更关键的是,Vue 生态里有 video.js、hls.js 这类成熟的播放器方案,对接 m3u8 流媒体播放几乎是开箱即用。
前后端分离还有一个实际好处: 答辩演示的时候,你不需要一台电脑同时跑两个服务,前端静态页面 + 后端 API 分开部署,任何一个环节出问题都不至于全盘崩掉。 这在我带过的毕业设计里,真的是个很现实的加分项。
1.2 系统整体架构和核心链路
整个系统的数据流你可以这样理解:浏览器访问 Vue 页面,Vue 通过 axios 请求 Django 提供的 RESTful API,Django 处理请求后从数据库取值返回 JSON,Vue 拿到数据渲染页面。视频文件本身不走数据库,而是单独存储在服务器的 media 目录或者对象存储里,数据库只保存视频文件的地址。
这么设计的原因是视频文件动辄几百 MB 甚至几个 GB,MySQL 这类关系型数据库对二进制大文件的读写性能非常差,而且会让数据库备份变得非常痛苦。 把文件路径存进数据库、文件实体放磁盘,这是所有视频系统的通用做法。
播放链路是另一个关键点。如果你用的是 m3u8 格式的流媒体,播放器拿到的是一个索引文件地址,然后根据索引去请求一个个 ts 分片。这个链路上任何一个环节没配好 CORS,播放器就会黑屏。这个细节我后面单独展开讲。
2. 核心功能模块与数据库建模
2.1 功能模块划分
点播平台和直播平台不一样,前者核心是“用户自主选择视频、随时播放”,所以功能设计围绕这个目标展开。我建议你把功能拆成三个端:
- 用户端 :注册、登录、浏览视频列表、按分类筛选、关键词搜索、播放视频、发表评论、收藏视频、查看播放历史。
- 管理端 :视频上传、视频信息编辑(标题、封面、分类、简介)、上下架管理、用户管理、评论管理。
- 公共模块 :首页推荐位、热门视频排行、分页加载。
这里面每做一个模块都有对应的技术考点:注册登录考认证与权限,搜索考 ORM 查询,收藏和评论考外键关联,播放历史考时间排序。 这些点你在答辩时随便挑两三个讲清楚,老师就能看出你是真的写了代码,而不是网上下的源码。
2.2 数据库表结构设计
数据库设计我建议用 5 张核心表,不需要过度设计。以 Django 自带的 User 表为基础,扩展出业务表:
| 表名 | 核心字段 | 说明 |
|---|---|---|
| users_user(Django 内置表) | username、password、email、date_joined | 继承 AbstractUser,可扩展头像、昵称字段 |
| video_category | name、sort_order | 视频分类,比如电影、电视剧、纪录片 |
| video_video | title、cover_url、video_url、category_id、desc、play_count、is_published、created_at | 核心视频表 |
| video_comment | video_id、user_id、content、created_at | 评论表,外键关联视频和用户 |
| video_favorite | video_id、user_id、created_at | 收藏表,联合作唯一约束 |
在设计 video 表时,有两点值得注意。第一点是 play_count 这个字段,很多人喜欢用 count() 去实时统计播放量,但一旦数据量上来,每次播放都 count 一次会拖垮性能。直接在表里加一个整型字段,播放时 F('play_count') + 1 原子性更新,这才是合理做法。第二点是 is_published 字段,用于上下架管理,管理员下架视频后,用户端不能展示,但数据库记录不删除,方便后续重新上架。
分类表和视频表是外键关系,评论表、收藏表也都通过外键关联用户和视频。这些关系设计好了,后面用 ORM 做关联查询会非常顺手。
3. Django 后端核心实现
3.1 项目初始化与 App 划分
后端我强烈建议你用虚拟环境隔离依赖,避免把系统 Python 环境搞乱。项目结构上分成三个 App: users 、 videos 、 comments 。
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Windows 下是 venv\Scripts\activate
# 安装 Django 和 DRF
pip install django djangorestframework django-cors-headers
# 创建项目
django-admin startproject video_website
cd video_website
# 创建 App
python manage.py startapp users
python manage.py startapp videos
python manage.py startapp comments
App 划分的原则是 按业务功能切,而不是按代码层切 。很多新手容易把所有代码写进一个 App,然后 model.py 几百行,views.py 上千行,后期自己都看不懂。拆成三个 App 后,每个 App 各管一摊,代码可读性会好很多。
3.2 REST API 设计与 DRF 应用
后端接口我推荐用 Django REST Framework(DRF)来实现,它能把序列化、验证、视图逻辑打包好,避免你写一堆重复代码。
以视频列表接口为例,核心实现是这样:
# videos/views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from .models import Video
from .serializers import VideoSerializer
class VideoViewSet(viewsets.ModelViewSet):
"""视频视图集,支持列表、详情、搜索、分类筛选"""
queryset = Video.objects.filter(is_published=True)
serializer_class = VideoSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
queryset = super().get_queryset()
# 分类筛选
category_id = self.request.query_params.get('category_id')
if category_id:
queryset = queryset.filter(category_id=category_id)
# 关键词搜索
keyword = self.request.query_params.get('keyword')
if keyword:
queryset = queryset.filter(title__icontains=keyword)
# 排序
ordering = self.request.query_params.get('ordering', '-created_at')
return queryset.order_by(ordering)
这个接口同时解决了列表、详情、搜索、分类筛选四个功能,靠的就是 DRF 的 ViewSet 和 URL 路由约定。
# video_website/urls.py
from rest_framework.routers import DefaultRouter
from videos.views import VideoViewSet
router = DefaultRouter()
router.register(r'api/videos', VideoViewSet)
urlpatterns = router.urls
关于权限控制,我建议用 IsAuthenticatedOrReadOnly ,意思是不登录也能看视频列表和播放,但写操作(上传、评论、收藏)必须登录。这是大部分视频网站的通用策略,也符合实际产品逻辑。用户认证推荐用 JWT(simplejwt 库),它能做到无状态认证,前后端分离场景下体验最好。
pip install djangorestframework-simplejwt
3.3 视频文件上传与播放地址设计
视频上传是毕设里最容易翻车的地方。Django 默认的请求体大小限制只有 2.5MB,直接上传视频必然报错。我在实践中的做法是先把限制调大,再配合前端做分片上传。
Django 这边做三件事:
# settings.py
# 调大上传限制
DATA_UPLOAD_MAX_MEMORY_SIZE = 104857600 # 100MB
FILE_UPLOAD_MAX_MEMORY_SIZE = 104857600
# 媒体文件配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# videos/models.py
def video_upload_path(instance, filename):
"""按日期目录存储,避免单目录文件过多"""
return f'videos/{timezone.now().strftime("%Y%m%d")}/{filename}'
class Video(models.Model):
video_file = models.FileField(upload_to=video_upload_path)
在实际开发时,小文件直接上传没问题,但如果要做大视频点播,我强烈建议在服务端集成 ffmpeg,把上传的 mp4 转成 m3u8 切片格式。尺寸不太大的话,一行命令就能完成:
ffmpeg -i input.mp4 -codec copy -hls_time 10 -hls_list_size 0 output.m3u8
m3u8 的核心优势是支持拖动播放到任意位置、带宽自适应,而且播放器加载压力远小于直接播放几百 MB 的 mp4 文件。这也是主流视频平台都用它的原因。如果你的毕设时间紧张,可以只在管理员上传时用这个命令做一次转码,播放逻辑保持不变。
4. Vue 前端核心实现
4.1 项目创建与依赖选型
前端用 Vue 3 配合 Vite 创建项目,比 Vue CLI 启动快很多。
npm create vite@latest video-frontend -- --template vue
cd video-frontend
npm install vue-router@4 axios
npm install video.js @videojs/http-streaming
UI 组件库我建议用 Element Plus 或者 Ant Design Vue。这两个库都有现成的表格、表单、分页组件,能让你把时间省到业务逻辑上,而不是花在写样式上。我用的是 Ant Design Vue,它的视觉风格偏稳重,适合视频网站这种内容型产品。
4.2 路由设计与登录态管理
前端路由按模块划分,核心页面有五个:首页、视频列表页、视频详情播放页、登录注册页、个人中心页。
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{ path: '/', name: 'Home', component: () => import('../views/Home.vue') },
{ path: '/videos', name: 'VideoList', component: () => import('../views/VideoList.vue') },
{ path: '/video/:id', name: 'VideoDetail', component: () => import('../views/VideoDetail.vue') },
{ path: '/login', name: 'Login', component: () => import('../views/Login.vue') },
{ path: '/me', name: 'Profile', component: () => import('../views/Profile.vue') },
]
登录态管理我推荐用 Pinia(Vue 3 官方推荐的状态管理库),把 token 和用户信息存到 localStorage。axios 请求拦截器里注入 token,响应拦截器里处理 401 状态并跳回登录页。这一步非常重要,不然用户登录后刷新页面就掉登录,体验很糟糕。
4.3 播放器接入 m3u8 流媒体
视频播放是点播平台的核心页面,这里坑最多。视频详情页的语法如下:
<template>
<div class="player-container">
<video
ref="videoPlayer"
class="video-js vjs-big-play-centered"
controls
playsinline
></video>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import videojs from 'video.js'
import '@videojs/http-streaming'
const videoPlayer = ref(null)
const props = defineProps({
src: { type: String, required: true },
})
let player = null
onMounted(() => {
player = videojs(videoPlayer.value, {
sources: [{
src: props.src,
type: 'application/x-mpegURL', // m3u8 必须用这个 mime type
}],
controls: true,
fluid: true,
preload: 'auto',
})
})
</script>
注意关键点:m3u8 播放必须依赖 @videojs/http-streaming 插件,并且 type 必须是 application/x-mpegURL 。这两个条件缺一个,播放器就会黑屏。
另外,视频接口返回的字幕和封面字段,可以通过 video.js 的选项直接挂载,不用另外写逻辑。
4.4 解决开发环境跨域问题
前后端分离开发时,最头疼的就是跨域。浏览器会拦截前端向不同端口发起的请求。我的解决方案是开发环境用 Vite 代理,生产环境用 Nginx 代理。
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
},
'/media': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
},
},
},
})
后端 Django 这边还要配合安装 django-cors-headers,不然即使有代理,某些场景下还是会有 CORS 报错。
# settings.py
INSTALLED_APPS = [
...
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
CORS_ALLOWED_ORIGINS = [
'http://localhost:5173',
]
两个代理配置完成后,前端代码里所有请求都写 /api/xxx ,开发时 Vite 把请求转发给 Django,打包部署时 Nginx 把请求转发给后端服务,前端代码完全不用改。
5. 常见问题与排查技巧
5.1 视频上传失败或超时
症状 :上传几十 MB 的视频文件时,请求直接 502 或者连接重置。
原因 :这个问题通常不是后端逻辑问题,而是开发服务器或 Nginx 的请求体大小限制。Django 自带的开发服务器处理大文件性能很弱,生产环境用 Nginx 时没配置 client_max_body_size 。
解决 :开发环境下用 python manage.py runserver --noreload 启动,可以缓解部分问题;如果用 Nginx 部署,必须加:
server {
client_max_body_size 200m;
}
建议 :如果你的视频文件经常超过 200MB,不要执着于单次上传,改成前端切片分片上传是更稳妥的方案。把文件切成 5MB 的块,一块一块传,后端每块校验后合并。这个方案对大视频平台来说是标配。
5.2 m3u8 播放黑屏
症状 :视频详情页打开后,播放器区域一片黑,控制台报错提示跨域或者 404。
原因 :这个问题的排查优先级最高的不是播放器代码,而是后端响应头。m3u8 的 ts 分片请求是浏览器发出的,浏览器对跨域资源有严格限制。如果你的后端和前端在同一个域名下(通过 Nginx 代理),一般没问题;但如果前后端分开部署在不同域名,Django 这边就要处理 OPTIONS 预检请求。
处理顺序 :先看浏览器控制台有没有 CORS 报错,有就配后端的 CORS_ALLOWED_ORIGINS ;没有就打开 Network 面板,看 m3u8 地址返回的是什么状态码,逐个排查。
经验 :我遇到最多的情况其实是开发环境代理没把 /media 路径代理过去,导致播放器请求到的是 404。你把 vite.config.js 里的 /media 代理配上基本就解决了。
5.3 Django 版本和 Python 环境的坑
症状 : pip install 报错,或者 python manage.py runserver 启动后各种模块找不到。
原因 :Django 5.x 对 Python 版本有要求,如果你系统里同时装了 Python 3.8 和 3.12,pip 安装的包可能会装到不同版本下面去。另一个常见问题是项目目录下没有激活虚拟环境就执行命令。
建议 :管理 Python 项目的标准姿势是:
# 一定要用虚拟环境
python -m venv venv
source venv/bin/activate
# 把依赖固定到 requirements.txt
pip freeze > requirements.txt
心得体会 :每个 Django 项目都应该有自己的虚拟环境,永远不要直接往系统 Python 里 pip install。我现在所有新项目的第一动作就是建虚拟环境,这个习惯已经帮我避开了无数依赖冲突的坑。
6. 项目部署与答辩展示建议
6.1 实际部署方案
毕设演示最稳的方式是部署到一台 Linux 服务器上(阿里云、腾讯云的轻量服务器都够用)。整体部署思路如下:
后端用 Gunicorn 跑,Nginx 做反向代理:
pip install gunicorn
gunicorn video_website.wsgi:application -b 127.0.0.1:8000
Nginx 配置同时管前端静态文件和 API 代理:
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /var/www/video-frontend/dist;
try_files $uri $uri/ /index.html;
}
# 后端 API
location /api {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 媒体文件
location /media {
alias /path/to/media;
}
}
部署这个步骤在答辩的时候是很好的加分项,至少说明你这个项目不只是一个本地产物,而是真的能跑在服务器上给用户访问的完整网站。
6.2 答辩时怎么讲才能拿高分
根据我带毕设的实际经验,答辩老师通常最关心三件事: 方案是不是你自己定的、核心功能是不是你写的、遇到问题是不是你自己排查解决的。
我建议你准备一份五分钟左右的功能演示路线:先讲首页和视频列表(展示前端效果),再播放一个视频(展示流媒体播放链路),最后切到管理端上传一个视频(展示完整闭环)。这条路线走完,整个项目“能看、能播、能传”的核心价值就全部体现了。
其次是准备好“为什么这样设计”的答案。比如:为什么用 JWT 不用 session?为什么用 m3u8 不用直接放 mp4?为什么前后端分离?这些问题你按照我前面讲的设计思路回答,老师会觉得你是有深度思考的,不是单纯抄代码。
7. 写在最后的经验总结
我做完这个项目后最大的感受是: 视频点播系统是一个非常适合做毕业设计的选题,因为它覆盖面广、技术栈主流、且具有明确的产品价值。 但你一定要把精力放在核心链路上,也就是“视频能不能顺利上传、能不能流畅播放、用户能不能正常互动”这三件事,而不是在美化页面样式上花太多时间。
我在实际开发中踩过的最大一个坑,是前期把精力都花在做了一个很炫的首页轮播图,结果到了联调阶段发现播放器接不上后端的数据,最后熬夜改接口。所以我的建议是:从第一天开始就按“前端页面收到真实的 API 数据”这条主线来开发,而不是用静态假数据往后推。假数据会让整个项目看起来跑得很顺畅,但一接真接口就全是问题,越早接真实接口,问题就越早暴露、越容易修。
最后分享一个小技巧: 开发期间每完成一个功能,就提交一次 Git 记录,并且在提交说明里写清楚你做了什么、为什么这么做。 这个习惯不仅方便你自己回溯,答辩时老师问开发流程,你也能拿出完整的版本迭代记录来佐证工作量,这在评分的时候是非常加分的细节。希望这篇文章能帮你把这个项目做顺,而不是做“累”。
更多推荐

所有评论(0)