Python+Django视频点播网站毕设全流程:环境配置到答辩演示

发布时间:2026/10/10 0:16:50
Python+Django视频点播网站毕设全流程:环境配置到答辩演示 简介一个基于Python与Django框架构建的视频点播网站系统面向毕业设计、课程设计或Django Web开发练习场景提供完整可运行的前后端代码与数据解压后可参考说明快速配置并启动。系统实现了视频列表展示、播放详情、用户评论、个人中心等前端模块以及视频、评论、用户、反馈管理等后台功能通过Django内置ORM、Admin后台和认证机制可方便地完成内容维护、权限控制与用户交互同时涵盖SQL注入与XSS防护等安全实践有助于理解真实项目的技术选型与工程结构。资源包共128个文件以48个HTML模板、40个Python源码、20个JavaScript脚本为主辅以CSS样式、PNG图片及配置文件HTML负责页面渲染、Python承载视图逻辑与数据模型、JS驱动前端交互压缩后仅3.23MB目录结构清晰适合按模块逐层阅读与二次开发。目前已有244人学习下载适合需要快速搭建可演示项目、梳理点播系统整体架构并完成毕设答辩的初学者参考。1. pythonDjango 视频点播网站系统这个毕设到底在考什么视频点播网站系统是毕设选题里出现频率最高的方向之一一个项目把用户注册登录、视频上传、分类管理、播放器嵌入、播放记录串在一起正好覆盖 Django 开发里最常被追问的考点。很多人看到「pythonDjango的视频点播网站系统 完整代码数据可直接运行 毕设」这个标题第一反应是找现成代码结果到答辩才发现功能能点但一问数据怎么流、视频为什么能播、表结构为什么这么设计就答不上来。代码可以直接跑只是起点能讲清楚才是及格线。这个方向适合两类人。一类是 Django 刚入门、需要一个完整项目练手的新手跟着把每个模块拆开重写一遍另一类是时间紧、需要在已有骨架上快速补功能和写文档的毕业生。视频点播难在动手不难在理解——把 Django 的 MTV 结构和媒体文件处理这两块吃透剩下的就是重复劳动。这篇文章不假装有现成源码包按我平时带模拟项目X的落地路径把环境版本选型、数据库表设计、视频上传与存储、播放器对接、常见翻车现场和答辩演示技巧逐段讲清楚每一步都给出可复现的命令与参数。先从头捋一遍完整链路你会发现这其实是个很朴素的 CRUD 加文件处理项目远没有想象中复杂。2. 环境选型与项目骨架Django 版本、数据库和最小可运行结构很多毕设跑不起来一半原因出在环境而不是代码。拿到项目先别急着装依赖先确认 Python 版本和 Django 版本是否匹配。我见过不止一个同学把 Django 装成最新版结果项目里用的第三方库还没适配迁移一跑就报错。版本这件事属于典型的「后悔药」问题——装错了最多花十分钟重装但答辩前夜遇到就很被动所以开篇先把它定死。2.1 Python 与 Django 版本怎么搭配别用最新版写视频点播网站系统我一般建议用 Python 3.10 配 Django 4.2 LTS这是一组经过大量项目验证的组合。Django 4.2 是长期支持版本官方维护到 2026 年文档和社区问答数量都够遇到问题搜得到答案。相比之下 Django 5.x 虽然新但部分第三方库尤其是数据库驱动和上传相关组件适配进度不一没必要拿答辩去赌兼容性。组合适合场景说明Python 3.8 Django 3.2接手老代码3.2 是上一代 LTS兼容性最好Python 3.10 Django 4.2新写毕设当前最稳的组合推荐Python 3.12 Django 5.x尝鲜踩坑需要自己填答辩前不推荐数据库方面视频点播系统用 SQLite 也能跑通但我会优先选 MySQL。原因有两个一是 MySQL 更接近真实生产环境答辩时被问「数据库为什么选这个」有得讲二是 Django 的 ORM 在 MySQL 下的行为是大多数教程和面试题的默认语境切换到 PostgreSQL 反而偏门。MySQL 版本选 8.0字符集在建库时指定 utf8mb4后面能避开中文乱码的麻烦。Python 版本一旦定下来虚拟环境里就固定用它不要同时装多个解释器来回切换。我见过有人系统里 Python 3.7、3.9、3.12 并存pip install 装到了 3.9 的 site-packages跑项目用的却是 3.12报错提示完全对不上号。这种环境层面的黑匣子问题排查起来比代码 bug 更折磨人。2.2 一分钟搭出项目骨架django-admin 与虚拟环境的正确姿势无论手头有没有现成代码我都建议先自己把骨架搭一遍这是理解项目结构最快的方式。虚拟环境从零创建避免污染系统全局的 Python 环境也方便最后导出 requirements.txt 交给评委复现。# 创建虚拟环境并激活Windows 下激活命令不同 python -m venv vod_env source vod_env/bin/activate # Windows: vod_env\Scripts\activate # 安装 Django 4.2 LTS 和 MySQL 驱动 pip install django4.2 pip install mysqlclient这里有个细节pip install django不带版本号会把最新的 5.x 装上所以一定要带4.2。mysqlclient 在 Windows 上偶尔会编译失败如果报错缺少 Visual C 工具可以换成pip install pymysql然后在项目__init__.py里加两行import pymysql; pymysql.install_as_MySQLdb()效果等价。# 创建项目和应用 django-admin startproject vod_site cd vod_site python manage.py startapp videostartproject生成了全局配置目录vod_sitestartapp生成业务应用video。视频点播相关的模型、视图、模板都放在video应用里全局配置只保留 settings、urls 和 wsgi/asgi。这个分层对应 Django 的 MTV 架构Model 负责数据、Template 负责展示、View 负责业务逻辑答辩时能把这个讲清楚比背概念有用得多。项目骨架生成后第一件事是去settings.py里注册应用把video加进INSTALLED_APPS然后配置数据库连接和媒体文件路径。数据库配置这块SQLite 是零配置的但如果用了 MySQL务必确认DATABASES里的OPTIONS配了charset: utf8mb4否则中文数据写入会报错或乱码。# settings.py 关键配置应用注册、数据库、媒体路径 INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, # ... 默认应用 video, # 业务应用 ] DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: vod_db, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } } # 媒体文件上传封面和视频的统一存放目录 MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / mediaMEDIA_ROOT是文件在磁盘上的物理路径MEDIA_URL是浏览器访问时的 URL 前缀。这两个值配错是后面 404 的头号原因后面第五章会专门讲。数据库密码不要用真实的服务器密码本地开发随便起一个但记得别写进提交的文档里。2.3 视频点播的四张核心表Category、Video 与播放记录的字段设计视频点播网站系统的数据模型其实很常规核心就四张表分类、视频、用户、播放记录。用户表直接用 Django 内置的auth.User不需要自己写用户模型——除非毕设要求做个性化头像、手机号登录之类扩展那也建议通过OneToOneField扩展 Profile 表而不是改 User 本身。# video/models.py 核心模型 from django.db import models from django.contrib.auth.models import User class Category(models.Model): 视频分类比如教程、电影、纪录片 name models.CharField(max_length50, uniqueTrue) sort models.IntegerField(default0, help_text数字越小越靠前) class Meta: ordering [sort, id] def __str__(self): return self.name class Video(models.Model): 视频本体标题、分类、封面、文件、播放次数 title models.CharField(max_length200) category models.ForeignKey( Category, on_deletemodels.SET_NULL, nullTrue ) cover models.ImageField(upload_tocovers/, blankTrue) file models.FileField(upload_tovideos/) desc models.TextField(blankTrue) is_active models.BooleanField(defaultTrue) play_count models.IntegerField(default0) created_at models.DateTimeField(auto_now_addTrue) class Meta: ordering [-created_at] def __str__(self): return self.title class PlayRecord(models.Model): 播放记录用于续播和观看历史 user models.ForeignKey(User, on_deletemodels.CASCADE) video models.ForeignKey(Video, on_deletemodels.CASCADE) progress models.FloatField(default0) # 单位秒 updated_at models.DateTimeField(auto_nowTrue) class Meta: unique_together (user, video)字段设计有三个点值得说。第一Category外键用SET_NULL而不是CASCADE因为删除分类不应连带删除视频这在答辩里是很好的细节回答点。第二progress用 FloatField 存秒数而不是存百分比因为前端播放器的currentTime本身是秒写百分比还要乘时长多一步转换容易出错。第三unique_together保证同一个用户对同一视频只保留一条记录每次播放更新进度而不是插新行避免历史记录无限膨胀。模型定义完执行迁移python manage.py makemigrations video python manage.py migratemakemigrations生成迁移文件migrate把迁移应用到数据库。如果这两步报错优先检查数据库连接信息和字符集配置八成是 MySQL 那边的问题。迁移成功后把模型注册进 admin 后台# video/admin.py from django.contrib import admin from .models import Category, Video, PlayRecord admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display [id, name, sort] admin.register(Video) class VideoAdmin(admin.ModelAdmin): list_display [id, title, category, is_active, play_count] list_filter [category, is_active]注册后台的意义不仅是方便自己录数据更是给评委演示「后台管理」模块。视频点播网站系统的标题里虽然没写后台但 Django admin 几乎是白送的加分项演示上传视频时不用写前端表单直接在后台点几下就完成效果反而更干净。3. 视频上传与存储MEDIA_ROOT 配置与文件校验的完整写法骨架搭好、表结构落地接下来就到了视频点播系统最核心的部分视频文件怎么从用户手里进到服务器前端又怎么把它展示出来。这一步涉及的不仅是 Django 表单还有文件大小限制、格式校验、目录权限这些容易被忽略的细节。很多毕设在这里翻车不是上传动作没写而是文件传上去了但访问不到。3.1 文件上传的三重校验后缀、大小与编码Django 处理文件上传靠request.FILES表单里input typefile提交的文件会以InMemoryUploadedFile或TemporaryUploadedFile对象出现前者是小于 2.5MB 的小文件后者是大文件直接落盘。视频文件通常都超过 2.5MB所以你会拿到临时文件对象它拥有name、size、content_type几个常用属性校验就基于它们。# video/views.py 上传视图 import os from django.views import View from django.shortcuts import render, redirect from .models import Video class VideoUploadView(View): def get(self, request): return render(request, video/upload.html) def post(self, request): title request.POST.get(title) category_id request.POST.get(category) cover request.FILES.get(cover) file request.FILES.get(file) # 第 1 重校验后缀白名单 allowed_ext [.mp4, .mov, .webm] ext os.path.splitext(file.name)[-1].lower() if ext not in allowed_ext: return render(request, video/upload.html, {error: 不支持的视频格式}) # 第 2 重校验文件大小视频限 500MB if file.size 500 * 1024 * 1024: return render(request, video/upload.html, {error: 视频不能超过 500MB}) # 第 3 重校验封面大小和格式 if cover and cover.size 2 * 1024 * 1024: return render(request, video/upload.html, {error: 封面不能超过 2MB}) Video.objects.create( titletitle, category_idcategory_id, covercover or None, filefile, is_activeTrue, ) return redirect(video_list)这段代码把校验分成三层后缀白名单、视频大小、封面大小。后缀白名单比content_type靠谱因为浏览器上报的 MIME 类型可以被伪造而文件名后缀至少有约束作用。cover or None的写法处理了「封面可选」的情况避免ImageField收到空字符串报错。参数说明500 * 1024 * 1024是 500MB这是 Django 默认FILE_UPLOAD_MAX_MEMORY_SIZE的 200 倍意味着这么大的文件会被完整写到临时目录再转存如果服务器磁盘空间不足会直接失败。本地跑毕设问题不大但如果你要部署到低配云主机建议把这个值降到 200MB 以内。真正生产级的方案是走对象存储直传但毕设场景下本地存储足够后面 3.3 节会讲取舍。还有一点要注意Video.objects.create里传filefile时Django 会按upload_tovideos/把文件写入MEDIA_ROOT/videos/目录文件对象被保存到数据库只是存了一个路径字符串。所以删除记录时文件并不会自动删除需要手动清理这一点在第五章的「坑」里会详细说。3.2 MEDIA_ROOT 与 MEDIA_URL配置错一步前端就 404上传之后就是访问。前面settings.py里配了MEDIA_ROOT和MEDIA_URL但光配这两个还不够Django 默认不会在开发服务器上托管媒体文件需要在根路由里手动挂载。这一步经常被遗漏结果就是 admin 后台能看到已上传的视频但点开 URL 直接 404。# vod_site/urls.py 根路由 from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns [ path(admin/, admin.site.urls), path(, include(video.urls)), ] # 开发环境托管媒体文件的关键一行 if settings.DEBUG: urlpatterns static( settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT )static()是 Django 提供的开发环境辅助函数它本质上是把/media/xxx的请求映射到MEDIA_ROOT/xxx的物理文件。注意条件是settings.DEBUG为 True一旦关闭调试模式这段就失效——生产环境应该由 Web 服务器直接托管媒体目录不经过 Django。毕设答辩跑在本地DEBUGTrue没问题但如果评委问「生产环境怎么办」你要能说出「静态和媒体文件交给专门的文件服务处理Django 只负责业务接口」这句话。文件存进去了、URL 也挂了最后一道关卡是目录权限。Linux 和 macOS 下MEDIA_ROOT目录必须对运行 Django 的用户可写否则上传时报 Permission deniedWindows 下相对少见但也可能出现在C:\Program Files这类受保护目录里。我一般会在项目根目录建media/手动确认权限是 755 或 775。排查 404 时固定走三步先确认文件物理存在、再确认数据库里的file字段是相对路径而不是绝对路径、最后确认浏览器访问的 URL 前缀是/media/。三步走完99% 的问题能定位到static()没挂载或MEDIA_ROOT拼错。3.3 大视频要不要分片500MB 以内的上传方案取舍不少毕设需求书里写着「支持大视频上传」学生第一反应是上分片上传用 JavaScript 把文件切成 5MB 一块逐块 POST最后后端合并。这个方案技术含量确实高但我得说句实在话如果题目没有明确要求本地部署的毕设完全没必要做分片。分片带来的复杂度是几何级上升的——块顺序、断点重传、合并失败、并发控制任何一个环节出问题都够你排查一整天。我建议的分级方案是这样视频文件控制在 500MB 以内用 3.1 节那种常规表单上传就够。Django 后端对 POST 体大小有限制DATA_UPLOAD_MAX_MEMORY_SIZE默认 2.5MB 只影响请求体文件上传走的是FILE_UPLOAD_MAX_MEMORY_SIZE和FILE_UPLOAD_TEMP_DIR所以只要临时目录够用大文件上传不会因为请求体限制被拒。真正需要担心的只有时间——500MB 在本地局域网环境下也就十几秒完全可控。如果需求书确实写了「支持断点续传」那就用最简化的分片前端用File.slice切块后端每个分片单独存成临时文件全部传完后按序号合并。下面给一个后端合并的核心片段足够应付答辩演示# video/views.py 分片合并简化版供答辩演示用 import os from django.conf import settings def merge_chunks(chunk_save_dir, target_name, total_chunks): 按序号把所有分片合并成一个完整文件 target_path os.path.join(settings.MEDIA_ROOT, videos, target_name) with open(target_path, wb) as outfile: for i in range(1, total_chunks 1): chunk_path os.path.join(chunk_save_dir, f{target_name}.part{i}) with open(chunk_path, rb) as infile: outfile.write(infile.read()) os.remove(chunk_path) # 合并后删除分片释放空间 return target_path这段代码是分片合并的核心动作按part1到partN顺序读取、写入同一个文件、边写边删临时分片。实际做分片上传还要处理「同一文件并发上传导致分片交错」的问题常见做法是前端生成唯一upload_id后端按upload_id建独立目录存放分片。答辩时你把这两点讲出来——合并顺序和并发隔离——就足以证明你理解分片的本质不必真把断点续传做得面面俱到。4. 播放链路打通播放器嵌入、进度续播与站内搜索视频存到了服务器接下来是用户最关心的环节能不能在网页上点开就播、播到一半关掉下次接着看、以及怎么从一堆视频里找到想看的。这三件事分别对应播放器选型、播放记录上报、搜索过滤是把「上传」这个动作闭环成「点播」系统的关键一步。4.1 播放器选型HTML5 video 够用还是得上第三方库视频点播系统的播放器选型我见过两种极端一种是用原生video标签什么库都不引另一种是一上来就上 flv.js、hls.js、video.js 全家桶。前者在遇到非 MP4 格式时会白屏后者把简单问题复杂化调试起来全是黑匣子。我的建议是视频统一转成 H.264 编码的 MP4播放器用原生video标签最多加一个poster封面属性。!-- video/templates/video/detail.html 播放器片段 -- video idplayer controls preloadmetadata poster{{ video.cover.url }} src{{ video.file.url }} stylewidth: 100%; max-height: 70vh; background: #000; /videopreloadmetadata表示页面加载时只获取视频的元信息时长、尺寸不预加载正片内容这样列表页点进来不会卡。poster用封面图占位用户没点播放前看到的是一张封面而不是黑洞洞的区域。controls属性调出浏览器自带的播放控件进度条、音量、全屏都有不需要写一行 JS。为什么只推荐 MP4 里的 H.264 编码因为这是浏览器兼容性最好的组合Chrome、Edge、Firefox 全部原生支持。如果你上传的是.mkv或.aviChrome 直接拒绝播放表现就是播放器黑屏或显示「没有支持的视频格式」。解决办法不是写代码而是用 FFmpeg 转码一行命令解决ffmpeg -i input.mkv -c:v libx264 -c:a aac -movflags faststart output.mp4-movflags faststart把文件的元数据移到文件头部这样浏览器可以边下边播不需要等整个文件下载完。如果没有这个参数网络差的时候播放器会长时间转圈。转码这件事属于毕设里最容易被忽视的环节很多人的代码没问题但视频文件格式不对整个演示就卡在播放器黑屏这一步。4.2 播放进度上报与续播5 秒节流一次最省事续播功能需要一个上报机制播放器每隔一段时间把当前播放位置发给后端下次用户再打开同一个视频时后端把这个位置返回播放器直接跳到那里。这里最大的坑是上报频率——有人监听timeupdate事件每一秒就发一次请求结果一个视频看完发了上千个 POST数据库里全是无意义的中间记录。// video/static/js/player.js 播放进度上报 let lastReportTime 0; const player document.getElementById(player); const videoId player.dataset.videoId; const csrftoken document.querySelector([namecsrfmiddlewaretoken]).value; player.addEventListener(timeupdate, function () { const now Date.now(); if (now - lastReportTime 5000) return; // 5 秒上报一次节流 lastReportTime now; const progress Math.floor(player.currentTime); fetch(/video/api/report/${videoId}/, { method: POST, headers: { X-CSRFToken: csrftoken, Content-Type: application/x-www-form-urlencoded, }, body: progress${progress}, }); });核心逻辑在if (now - lastReportTime 5000) return这行5 秒内的timeupdate事件全部忽略只有距离上次上报超过 5 秒才发一次。这样一部 40 分钟的视频最多产生 480 条记录数据库完全扛得住。fetch里带上了 CSRF Token这是 Django 的硬性要求漏掉会报 403。注意player.dataset.videoId的取值方式——我在模板里给video标签加了># video/views.py 播放记录接口 from django.http import JsonResponse from django.views.decorators.http import require_POST from .models import PlayRecord, Video require_POST def report_progress(request, video_id): progress request.POST.get(progress, 0) PlayRecord.objects.update_or_create( userrequest.user, video_idvideo_id, defaults{progress: float(progress)}, ) return JsonResponse({status: ok}) def get_resume_point(request, video_id): record PlayRecord.objects.filter( userrequest.user, video_idvideo_id ).first() progress record.progress if record else 0 return JsonResponse({progress: progress})update_or_create是 Django 提供的神器一条语句完成「存在就更新不存在就创建」正好对应模型里unique_together的设计。需要说明的是续播逻辑一般只在未看完时生效所以前端拿到progress后要和视频时长比较如果进度超过总时长 95% 就直接归零从头播否则每次打开都从结尾开始会很奇怪。4.3 搜索与同类推荐Q 对象实现标题模糊检索搜索是视频站点的标配功能Django 的Q对象做模糊检索非常顺手。常见做法是对title和desc两个字段做icontains匹配icontains在 MySQL 里对应LIKE %关键字%大小写不敏感。还有一个容易被忽略的点搜索必须在is_activeTrue的过滤条件下进行否则后台下架的片子会出现在搜索结果里。# video/views.py 搜索与列表 from django.db.models import Q from django.core.paginator import Paginator from .models import Video def video_list(request): kw request.GET.get(q, ).strip() videos Video.objects.filter(is_activeTrue) if kw: # Q 对象标题或描述命中关键字 videos videos.filter( Q(title__icontainskw) | Q(desc__icontainskw) ) # 同类推荐同分类下播放量最高的 4 条 category_id request.GET.get(category) if category_id: videos videos.filter(category_idcategory_id) paginator Paginator(videos, 12) # 每页 12 条 page_obj paginator.get_page(request.GET.get(page)) return render(request, video/list.html, {page_obj: page_obj})videos.filter(...)的返回值是 QuerySet支持链式调用所以先过滤is_active再叠加关键字和分类顺序无所谓Django 最终会生成一条 SQL。Paginator(videos, 12)是列表页的性能底线——不加分页的话几百条视频还能扛几千条时页面加载会明显变慢第五章会专门讲这个坑。如果还有同类推荐的需求在详情页按category过滤、排除当前视频、按play_count排序取前几条即可逻辑和这里的分类过滤完全一致不增加学习成本。到这里上传、播放、续播、搜索四条主链路已经闭环接下来要面对的是把这条链路跑稳——也就是各种意想不到的坑。5. 视频点播系统最常见的 5 个坑现象、原因与解决方案前面几章把核心链路搭完了但凡是亲手跑过一遍的人都知道链路通不通和能不能稳定演示是两码事。这一章按我实际带模拟项目X和数据恢复时遇到过的高频问题整理一共 5 条全部按「现象 → 原因 → 解决」的顺序写方便你直接对照排查。5.1 上传后的视频前端 404 与播放黑屏媒体文件的经典坑现象后台能正常上传视频数据库里也能看到记录但前台页面打开视频地址返回 404或者 404 解决了播放器又是黑屏。原因404 基本可以确定是媒体文件没被 Django 托管。典型场景是settings.py里写了MEDIA_ROOT但根路由urls.py没加static()或者把部署配置里的DEBUGFalse直接套到了本地运行导致if settings.DEBUG分支被跳过。黑屏则是另一类问题——视频编码浏览器不支持.mkv、.avi、高规格 H.265 编码在 Chrome 里都播不了。解决404 就在根路由补上static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)确认DEBUGTrue。黑屏则统一走转码把视频压成 H.264 AAC 的 MP4用 4.1 节那条 ffmpeg 命令即可。排查时先按 F12 看 Network 面板里视频请求的响应状态码404 是路径问题200 但黑屏是编码问题这个区分能省一半排查时间。5.2 MySQL 迁移失败与中文乱码字符集和驱动的坑现象python manage.py migrate报Unknown collation或Character set utf8mb4 cannot be used或者迁移成功但写入中文后页面显示乱码。原因数据库本身没建对。MySQL 8.0 默认字符集是utf8mb4但如果建库时显式指定了utf8不是utf8mb4Django 连接时按utf8mb4写入就会报错。乱码则通常是表级别字符集和连接字符集不一致。解决在建库时一步到位不要用图形化工具默认值CREATE DATABASE vod_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;如果库已经建了用ALTER DATABASE vod_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;修改然后删掉原有的迁移记录重新migrate。还有一个细节mysqlclient 在 Python 3.10 以上偶尔编译失败按 2.2 节说的改用 pymysql在项目__init__.py里执行pymysql.install_as_MySQLdb()效果一致。5.3 前台列表空白is_active 过滤与管理员上传的默认值现象admin 后台能看到所有视频但前台首页和搜索列表一个视频都不显示或者有的视频显示了有的不显示。原因这是毕设里最常见也最隐蔽的逻辑坑。前台查询集几乎都带is_activeTrue过滤但如果你通过 admin 后台或直接objects.create上传时没有显式传is_activeTrue而模型字段默认值是True按理不该出问题——真正的坑在于你后来可能手动勾掉了这个字段或者在导入数据时is_active被写成了False、字符串False、甚至数字0。解决先用一条命令查清事实python manage.py shell -c from video.models import Video; print(Video.objects.values_list(id,title,is_active))看到is_active为 0 的记录批量修正Video.objects.filter(id__in[...]).update(is_activeTrue)。以后规范做法是上传视图里永远显式指定is_activeTrueadmin 后台审核下架时才去改这个字段。这个坑几乎每个做视频站的人都会踩一次因为「后台有、前台没有」的问题太容易让人怀疑是 URL 或模板配错方向从一开始就跑偏了。5.4 视频列表加载越来越慢N1 查询与缺少分页现象上传了几十条视频后列表页打开要等两三秒视频越多越明显后台请求日志里能看到一次列表请求背后跟着几十条 SQL。原因典型的 N1 查询。模板里遍历视频时访问了video.category.name这类外键字段Django 默认惰性加载每条视频都单独发一条 SQL 查分类。再加上列表没有分页一次加载全部视频SQL 数量自然爆炸。解决查询集加select_related把外键一次性 JOIN 出来同时强制分页videos Video.objects.filter(is_activeTrue).select_related(category) from django.core.paginator import Paginator page_obj Paginator(videos, 12).get_page(request.GET.get(page))select_related(category)是解决 N1 的最简单手段适用于一对一和多对一外键。多对多场景要换prefetch_related这个区别答辩时也常被问到。分页不只是用户体验问题更是性能红线——我没有见过哪份像样的毕设是列表页不分页的这是最基本的工程习惯。5.5 删除视频后文件还占磁盘ORM 删除不等于文件删除现象后台删除了一条视频记录数据库没这条了但media/videos/目录下的文件还在磁盘空间越用越多。原因Django 的 ORM 删除只删数据库行不会动物理文件。FileField在模型里存的只是一个路径字符串ORM 没有能力也不负责清理实体文件。这个设计本身是合理的但对于毕设来说演示完大量试传的视频文件堆积最后可能把磁盘塞满。解决在模型里重写delete方法删除记录时同步清理文件# video/models.py import os from django.conf import settings class Video(models.Model): # ... 字段不变 def delete(self, *args, **kwargs): # 先记下文件路径再删记录 file_path os.path.join(settings.MEDIA_ROOT, self.file.name) cover_path os.path.join(settings.MEDIA_ROOT, self.cover.name) if self.cover else None super().delete(*args, **kwargs) # 记录删完后再清理物理文件 if os.path.exists(file_path): os.remove(file_path) if cover_path and os.path.exists(cover_path): os.remove(cover_path)注意顺序先调super().delete()删数据库行再动文件。如果先删文件再删记录删记录失败时文件已经没了数据会不一致。批量删除QuerySet.delete()不会触发单条模型的delete方法所以这个方案只覆盖后台单条删除要覆盖批量操作得用信号post_delete接收器那是进阶话题毕设做到重写delete已经足够说明你考虑过资源释放问题。6. 答辩演示从「能跑」到「能讲」验证路径与三个加分技巧代码跑通只是开始答辩时要让评委十分钟内看懂你做了什么靠的是演示顺序和讲法。这一章讲我怎么准备一场不出事故的演示以及怎么把题目里的几个关键词讲成加分项。6.1 用 Django admin 和 dumpdata 准备演示数据最尴尬的答辩现场就是打开网站发现列表是空的。我习惯提前用 admin 把分类和视频录好至少 3 个分类、每个分类 5 条以上视频封面齐全。数据准备好后用dumpdata导出成 fixture换机器演示时一条命令恢复python manage.py dumpdata video --indent 2 video/fixtures/init_data.json python manage.py loaddata video/fixtures/init_data.jsondumpdata只导出video应用的数据避免把用户密码等敏感信息也带走。视频文件本身不会进 fixture它只包含路径字符串所以换机器时要连media/目录一起拷。有这份 fixture 在手就算现场数据被弄乱也能一分钟恢复原样。6.2 演示顺序搜索、播放、续播、上传的固定节奏我兜底的演示路径是这样先打开首页展示分类和视频列表点进一部视频播放播放到 10 秒时暂停退出再重新点进来看续播是否从 10 秒开始然后回到首页搜索刚看的视频标题关键字展示搜索结果最后切到 admin 后台现场上传一个小视频回到前台确认能搜到、能播放。这套顺序正好覆盖「列表 → 播放 → 续播 → 搜索 → 上传」五条链路全程不碰代码编辑器节奏紧凑且不容易出错。如果评委中途打断问某个功能怎么实现再切到代码对应位置展示。千万不要一上来就滚代码先让别人看到「东西是能用的」再解释「它是怎么工作的」。演示前把浏览器缓存清一遍播放器每次都会重新加载 resources慢一点没关系但千万不要在演示时现场转码。6.3 答辩最容易被追问的三个技术点评委问来问去就三件事请求是怎么走的、文件是怎么存的、表是怎么设计的。对应到项目里用户点开一个视频 URL从浏览器发出请求到 Django 的 URL 路由再到 View 查询数据库返回模板渲染成 HTML上传的视频文件通过 FileField 写到 MEDIA_ROOT数据库只存路径四张表之间的关系是 Category 一对多 Video、Video 一对多 PlayRecord、User 一对多 PlayRecord。你只要脑子里有这三条线任何追问都能归结到其中一条回答就不会跑偏。我自己带项目时有个习惯答辩前两天会让自己走一遍这套演示流程并且故意制造一次故障比如删掉一个视频文件看页面怎么表现。这么做不是为了找刺激而是为了确认自己对报错信息有直觉——真正的翻车都不是功能没做而是演示现场出了状况不知道怎么应对。能处理意外往往比把功能做齐全更让评委认可。这个习惯我也建议你保留希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询