☰
基于Django+Vue的电影推荐系统毕业设计:协同过滤算法与前后端分离实战
2026/10/7 13:33:04 网站建设 项目流程

简介:这份资源面向计算机相关专业的毕业生与需要完成推荐系统课程设计的学习者,提供一套基于协同过滤推荐算法的电影推荐系统完整实现方案。项目采用Python+Django构建后端服务,Vue.js负责前端页面渲染,MySQL存储用户、电影与订单等业务数据,实现前后端分离架构。系统区分管理员与用户两种角色:管理员可管理用户、电影类型、电影信息、论坛交流与订单,用户可注册登录、浏览影片、选座预订、查看资讯并参与论坛留言。压缩包共708个文件,约13.05MB,包含39个Python源文件、37个Vue组件、51个CSS样式、162个JS脚本及配套SQL脚本,另附毕业论文、开题报告与安装运行批处理脚本,便于快速部署与二次开发。目前已有209人学习下载,适合作为毕业设计参考或推荐算法入门实战项目。

1. 从一份带 .bak 的源码包说起:这套电影推荐系统到底能跑出什么

如果你拿到的毕业设计压缩包里躺着一堆index.html.bak、update-password.vue.bak、IndexMain.vue.bak,先别急着删——这些.bak文件恰恰说明作者在交付前动过前端模板,改崩了又回滚过一轮。这套基于推荐算法、Python + Django + Vue + MySQL 的前后端分离电影推荐系统,本质是一个「管理员后台 + 用户前台」的双角色 Web 应用:管理员管用户、电影类型、电影信息、论坛、订单和系统配置,用户能注册登录、浏览电影、选座预订、看资讯、在论坛留言。它适合两类人:一是要交毕业设计、需要一份能跑通、能答辩、带论文和开题报告的同学;二是想拿一个真实前后端分离项目练手 Django REST 接口和 Vue 组件通信的入门开发者。源码、论文、开题报告都在包里,省掉的是从零搭架子那两周,留下的是你要真正读懂的推荐逻辑和接口链路。

2. 技术栈选型与目录结构:为什么是 Django + Vue 而不是别的

2.1 前后端分离的边界在哪

这套系统把 Django 当纯后端接口层用,Vue 负责所有页面渲染和路由跳转,两者靠 HTTP + JSON 通信。常见做法是 Django 侧用djangorestframework暴露 REST 接口,Vue 侧用axios发请求。为什么不用 Django 模板直接渲染?因为毕业设计答辩时,「前后端分离」本身就是一个加分的技术点,而且 Vue 的组件化让电影列表、选座、论坛这些模块拆得干净,改一个页面不会牵动后端。

选型上还有一层现实考虑:Python 生态里做推荐算法最顺手,numpy、pandas、scikit-learn都是现成的;MySQL 是最常见的 RDBMS,答辩老师不会追问「为什么不用 PostgreSQL」;Vue 的上手曲线比 React 平缓,vue-router和vuex的文档对新手友好。这套组合不是最优解,但是毕业设计场景下「能跑通 + 好解释 + 资料多」的最稳解。

2.2 目录里那些 .bak 和 .bat 是什么

先看包里的关键文件,别被.bak迷惑:

文件/目录作用要不要动
index.html.bak前端入口页备份一般不用,除非入口被改坏
update-password.vue.bak修改密码组件备份不用,正式文件是去掉 .bak 的
IndexMain.vue.bak首页主组件备份不用
IndexAsideStatic.vue.bak侧边栏静态组件备份不用
BreadCrumbs.vue.bak面包屑组件备份不用
安装.bat一键装依赖脚本首次运行要用
运行.bat一键启动脚本日常启动用
3-build.bat前端构建脚本改完前端要重新构建
2-run.bat启动脚本配合 build 用

.bak是备份文件,正式代码是去掉后缀的同名文件。.bat是 Windows 批处理,说明作者主要在 Windows 上开发。如果你在 Mac 或 Linux 上跑,.bat用不了,得手动执行里面的命令——这是第一个坑,后面避坑章节细说。

2.3 后端 Django 的 app 划分

Django 项目通常按功能拆 app。这套系统里,你能预期看到类似user(用户管理)、movie(电影信息与类型)、order(订单与选座)、forum(论坛交流)、recommend(推荐算法)这样的 app 划分。每个 app 下有models.py(数据表定义)、views.py(接口逻辑)、serializers.py(数据序列化)、urls.py(路由)。

推荐算法一般单独放一个模块,常见做法是在recommendapp 里写协同过滤或基于内容的推荐,然后在电影列表接口里调用它,给当前登录用户返回个性化排序。如果你打开views.py看到get_recommend_list(user_id)这类函数,那就是推荐入口。

2.4 前端 Vue 的组件结构

Vue 侧的核心是src/views下的页面组件和src/components下的通用组件。从.bak文件名能推断出:IndexMain.vue是首页主体,IndexAsideStatic.vue是侧边栏,BreadCrumbs.vue是面包屑,update-password.vue是修改密码页。路由配置在src/router/index.js,接口请求封装在src/utils/request.js或类似文件里,axios的 baseURL 指向 Django 的地址。

前后端联调的关键就一个:Vue 里axios请求的地址必须和 Django 实际监听的地址、端口一致。常见配置是 Django 跑在127.0.0.1:8000,Vue 开发服务器跑在127.0.0.1:8080,中间靠 CORS 或代理打通。

3. 环境搭建与启动:从安装.bat 到浏览器出页面

3.1 Python 与 Django 环境

先确认 Python 版本。Django 2.x 配 Python 3.6~3.8,Django 3.x 配 Python 3.6+,Django 4.x 要求 Python 3.8+。不确定版本时,先看requirements.txt里 Django 的版本号,再选对应的 Python。

# 查看 Python 版本,建议 3.8 及以上 python --version # 创建虚拟环境,避免污染全局 python -m venv venv # Windows 激活 venv\Scripts\activate # Mac/Linux 激活 source venv/bin/activate # 安装依赖,requirements.txt 在项目根目录 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

-i后面是清华镜像源,国内下载快很多。如果requirements.txt里某个包版本装不上,常见原因是 Python 版本不匹配,比如mysqlclient在 Windows 上需要额外装编译工具,这时可以换成pymysql,在__init__.py里加pymysql.install_as_MySQLdb()。

3.2 MySQL 建库与配置

MySQL 建议 5.7 或 8.0。8.0 的认证插件默认是caching_sha2_password,老版本 Django 可能连不上,需要改成mysql_native_password。

-- 登录 MySQL 后创建数据库,字符集用 utf8mb4 CREATE DATABASE movie_recommend DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 创建专用用户并授权,避免直接用 root CREATE USER 'movie_user'@'localhost' IDENTIFIED BY 'your_password'; GRANT ALL PRIVILEGES ON movie_recommend.* TO 'movie_user'@'localhost'; FLUSH PRIVILEGES;

然后在 Django 的settings.py里改数据库配置:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'movie_recommend', 'USER': 'movie_user', 'PASSWORD': 'your_password', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': {'charset': 'utf8mb4'}, } }

NAME必须和上面建的库名一致,OPTIONS里的utf8mb4是为了存中文和特殊字符不出乱码。改完执行迁移:

python manage.py makemigrations python manage.py migrate

如果迁移报错说表已存在,说明数据库里有旧数据,要么删库重建,要么用--fake跳过,但--fake有风险,新手建议直接删库重来。

3.3 前端 Vue 依赖安装与启动

Vue 项目在frontend或类似目录下,先看package.json确认是 Vue 2 还是 Vue 3。Vue 2 用npm install后npm run serve,Vue 3 类似但依赖版本不同。

# 进入前端目录 cd frontend # 安装依赖,用淘宝镜像加速 npm install --registry=https://registry.npmmirror.com # 启动开发服务器 npm run serve

启动后浏览器访问http://localhost:8080。如果页面空白,按 F12 看 Console 报错,常见是接口地址不对或跨域被拦。

3.4 前后端联调的关键配置

Django 侧要允许跨域。装django-cors-headers,在settings.py里加:

INSTALLED_APPS = [ # ... 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 放在最前面 # ... ] CORS_ALLOW_ALL_ORIGINS = True # 开发阶段图省事,上线要收紧

Vue 侧的axiosbaseURL 指向http://127.0.0.1:8000。如果不想改代码,也可以在vue.config.js里配代理:

module.exports = { devServer: { proxy: { '/api': { target: 'http://127.0.0.1:8000', changeOrigin: true, }, }, }, };

这样前端请求/api/movies/会被代理到 Django,避免跨域。changeOrigin: true是让代理带上正确的 Host 头,不加有时会被后端拒绝。

4. 推荐算法与核心接口:数据怎么流、推荐怎么算

4.1 推荐算法的常见实现路径

毕业设计里的推荐算法,常见做法是协同过滤(UserCF 或 ItemCF)或基于内容的推荐。协同过滤靠用户-电影评分矩阵算相似度,基于内容靠电影类型、标签匹配用户偏好。这套系统有「电影类型管理」和「订单」,说明用户行为数据(看过什么、订过什么)是有的,协同过滤有数据基础。

一个典型的 ItemCF 流程:先算电影之间的相似度,再根据用户看过的电影推荐相似电影。核心代码大致长这样:

import numpy as np from sklearn.metrics.pairwise import cosine_similarity def item_similarity(user_movie_matrix): # user_movie_matrix: 行是用户,列是电影,值是评分或行为权重 # 转置后行是电影,算电影间余弦相似度 item_matrix = user_movie_matrix.T sim = cosine_similarity(item_matrix) return sim def recommend_for_user(user_id, user_movie_matrix, item_sim, top_n=10): # 取该用户已看过的电影索引 watched = np.where(user_movie_matrix[user_id] > 0)[0] scores = {} for movie in watched: # 对每部看过的电影,找相似电影累加得分 sim_scores = item_sim[movie] for idx, s in enumerate(sim_scores): if idx not in watched: scores[idx] = scores.get(idx, 0) + s # 按得分排序取前 top_n ranked = sorted(scores.items(), key=lambda x: x[1], reverse=True) return [movie_id for movie_id, _ in ranked[:top_n]]

user_movie_matrix是用户-电影行为矩阵,值可以是评分、观看次数或是否购买。cosine_similarity算的是电影向量之间的夹角余弦,越接近 1 越相似。recommend_for_user里只对用户没看过的电影打分,避免推荐已看过的。top_n控制返回数量,一般 10 到 20 条。

如果数据量小,这套算法跑得很快;数据量大要考虑稀疏矩阵和离线计算,但毕业设计的数据量通常不用担心。

4.2 电影列表与推荐接口

Django 侧的电影接口一般分两个:普通列表和推荐列表。普通列表返回全部或按类型筛选的电影,推荐列表返回算法算出的个性化结果。

from rest_framework.decorators import api_view from rest_framework.response import Response from .models import Movie from .recommend import recommend_for_user, build_matrix @api_view(['GET']) def movie_list(request): movies = Movie.objects.all().values('id', 'title', 'type', 'cover') return Response(list(movies)) @api_view(['GET']) def recommend_list(request): user_id = request.user.id matrix = build_matrix() # 从订单/浏览记录构建矩阵 item_sim = item_similarity(matrix) ids = recommend_for_user(user_id, matrix, item_sim) movies = Movie.objects.filter(id__in=ids).values('id', 'title', 'cover') return Response(list(movies))

@api_view是 DRF 的装饰器,限定请求方法。request.user.id依赖登录态,所以推荐接口必须带 token 或 session。build_matrix()每次请求都重建矩阵效率低,常见优化是缓存矩阵,但毕业设计阶段可以先跑通再优化。

4.3 选座与订单接口

选座是这套系统里比较有业务味的部分。座位状态一般存在订单表或单独的座位表里,用户选座时先查已占座位,再锁定。

@api_view(['POST']) def create_order(request): movie_id = request.data.get('movie_id') seats = request.data.get('seats') # 如 ['A1', 'A2'] # 检查座位是否已被占 occupied = Order.objects.filter(movie_id=movie_id, seat__in=seats).values_list('seat', flat=True) if occupied: return Response({'error': f'座位 {list(occupied)} 已被占用'}, status=400) # 创建订单 for seat in seats: Order.objects.create(user=request.user, movie_id=movie_id, seat=seat) return Response({'msg': '预订成功'})

seat__in=seats是 Django ORM 的in查询,一次查出所有冲突座位。返回 400 让前端知道失败原因。这里没加事务,并发下可能两个请求同时通过检查,生产环境要用transaction.atomic()加锁,但毕业设计演示场景够用。

4.4 前端如何消费这些接口

Vue 侧用axios调接口,在组件mounted或created生命周期里发请求,拿到数据渲染列表。

import axios from 'axios'; export default { data() { return { movies: [], recommends: [] }; }, created() { axios.get('/api/movies/').then(res => { this.movies = res.data; }); axios.get('/api/recommend/').then(res => { this.recommends = res.data; }); }, };

created在组件实例创建后触发,此时 DOM 还没渲染,适合发请求。this.movies拿到数据后 Vue 自动更新视图。如果接口需要登录态,要在axios拦截器里统一加 token,避免每个请求手写。

5. 避坑与排查:那些让答辩前夜翻车的细节

5.1 现象:前端页面空白,Console 报 CORS 错误

原因:Django 没配跨域,或CorsMiddleware没放在MIDDLEWARE最前面。解决:装django-cors-headers,把corsheaders.middleware.CorsMiddleware放到CommonMiddleware之前,开发阶段设CORS_ALLOW_ALL_ORIGINS = True。

5.2 现象:MySQL 连接报Authentication plugin 'caching_sha2_password' cannot be loaded

原因:MySQL 8.0 默认认证插件和旧版 Django 的mysqlclient不兼容。解决:改用户认证方式ALTER USER 'movie_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';,或升级mysqlclient到支持新插件的版本。

5.3 现象:python manage.py migrate报表已存在

原因:数据库里有上次迁移的残留表,或迁移记录和实际表不一致。解决:开发阶段直接DROP DATABASE movie_recommend;重建,再migrate。别用--fake硬跳,后面会出更诡异的问题。

5.4 现象:.bat脚本双击闪退,看不到报错

原因:批处理执行完自动关窗口,错误信息一闪而过。解决:在.bat最后加pause,或直接在命令行里手动执行脚本里的命令,这样报错会留在终端里。Mac/Linux 用户直接忽略.bat,按第 3 章的命令手动跑。

5.5 现象:推荐结果每次刷新都一样,没有个性化

原因:推荐接口没取当前用户,或矩阵构建时没用用户行为数据。解决:确认request.user能拿到登录用户,检查build_matrix()是否真的读了订单/浏览记录,而不是返回固定矩阵。可以在函数里print矩阵形状和用户 id 排查。

6. 进阶:把推荐结果做成可解释的,答辩时多拿两分

答辩老师最爱问的一句是「你这个推荐算法怎么证明有效」。光说「用了协同过滤」不够,你得能展示推荐理由。一个具体技巧是:在推荐接口里除了返回电影列表,再返回「因为你看过 XX,所以推荐 YY」这样的解释字段。

def recommend_with_reason(user_id, user_movie_matrix, item_sim, movies, top_n=10): watched = np.where(user_movie_matrix[user_id] > 0)[0] scores = {} reasons = {} for movie in watched: sim_scores = item_sim[movie] for idx, s in enumerate(sim_scores): if idx not in watched: scores[idx] = scores.get(idx, 0) + s # 记录贡献最大的来源电影 if idx not in reasons or s > reasons[idx][1]: reasons[idx] = (movie, s) ranked = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_n] result = [] for movie_id, score in ranked: source_id, _ = reasons[movie_id] result.append({ 'movie': movies[movie_id], 'score': round(score, 3), 'reason': f"因为你喜欢《{movies[source_id]}》", }) return result

reasons字典记录每部候选电影得分贡献最大的来源电影,最后拼成一句人话。round(score, 3)保留三位小数,避免前端显示一长串浮点数。这个改动不大,但答辩演示时能直接指着页面说「这条推荐是因为你之前订过那部」,比干巴巴的列表有说服力。

验证推荐效果还有个土办法:准备两个测试账号,一个只看动作片,一个只看爱情片,分别登录看推荐列表是否分化。如果两个账号推荐结果高度重合,说明算法没真正用上用户行为,得回去查矩阵构建。我一般会在build_matrix()里加一行print(matrix.shape)和print(matrix[user_id]),确认这个用户的行不是全零。

从那以后我每次拿到这类毕业设计源码,都强制先跑一遍「注册两个账号 → 各自产生行为 → 对比推荐结果」这条链路,确认推荐是真的在算而不是写死的。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询