
简介这份毕业设计论文资源面向计算机相关专业的本科毕业生聚焦基于Python与协同过滤算法的电影推荐系统帮助读者完成从选题、系统设计到论文撰写的完整毕设流程。压缩包内共1个doc文件约2.43MB即论文正文文档涵盖摘要、绪论、系统设计与实现等章节可直接作为论文写作模板与参考范例。论文以Django框架与MySQL数据库为技术栈划分管理员与用户两类角色管理员负责个人中心、用户管理、电影分类与信息管理、电影评分管理及系统管理用户可注册登录、浏览电影资讯、评分、评论与收藏并借助协同过滤算法实现个性化推荐。内容预览显示论文结构完整包含中英文摘要、目录、研究背景与意义等规范模块对界面简洁美观、功能模块布局及数据安全方案均有论述。目前已有80人学习下载适合需要参考完整毕设论文结构、技术选型与功能模块划分的读者也可为推荐算法类课题的写作提供思路借鉴。1. 从一份 .doc 说起这套协同过滤电影推荐系统到底能跑出什么如果你正在为计算机毕业设计发愁或者手头拿到了一份名为「基于python和协同过滤算法的电影推荐系统.doc」的文档第一反应大概率是这玩意儿到底能不能跑起来里面写的协同过滤是真算法还是套壳我拆过不少这类毕设包说实话大部分文档写得像产品说明书真正能落地的代码逻辑藏在字缝里。这份文档的核心价值在于它给了一套完整的 Django MySQL 电影推荐系统骨架包含用户注册登录、电影分类管理、评分评论收藏以及最关键的协同过滤推荐模块。它适合两类人一是需要快速搭出一个能演示、能答辩的毕设系统的同学二是想拿一个现成的 Django 项目练手顺便把推荐算法从理论落到代码上的开发者。文档里提到的管理员和用户双角色、电影资讯管理、评分管理这些模块都是实打实要写进 models.py 和 views.py 的东西不是纸上谈兵。2. 环境搭建与 Django 项目初始化把文档里的技术栈跑通2.1 为什么选 Django MySQL 而不是 Flask SQLite文档里明确写了用 Django 框架和 MySQL 数据库这个选型在毕设场景下其实很合理。Django 自带 Admin 后台和 ORM你不需要从零写增删改查的 SQL模型定义好之后迁移一下后台管理界面直接就能用省下来的时间可以花在协同过滤算法上。MySQL 相比 SQLite 的优势在于它更接近生产环境答辩的时候老师问「你这数据存哪」你说 MySQL 并且能当场连上数据库看表结构比说 SQLite 要硬气得多。另一个现实原因是很多学校的毕设要求里明确写了「必须使用主流关系型数据库」MySQL 就是最稳妥的选择。安装环节我一般会建议用虚拟环境隔离依赖避免把系统 Python 搞乱。下面是 Ubuntu 和 Windows 下都通用的步骤Python 版本建议 3.8 到 3.10Django 用 3.2 LTS 或 4.2 LTS 都行MySQL 用 5.7 或 8.0 都可以但 8.0 的认证插件变化需要注意后面避坑章节会细说。# 创建项目目录并进入 mkdir movie_recommend cd movie_recommend # 创建虚拟环境Ubuntu/Windows 通用 python -m venv venv # 激活虚拟环境 # Ubuntu: source venv/bin/activate # Windows: # venv\Scripts\activate # 安装核心依赖 pip install django4.2.7 mysqlclient2.2.0 pandas2.1.1 numpy1.26.0 scikit-learn1.3.2 # 创建 Django 项目 django-admin startproject movie_system . # 创建核心应用 python manage.py startapp recommend这里解释一下几个关键依赖的作用。mysqlclient是 Django 连接 MySQL 的驱动比pymysql性能更好但安装时依赖系统里的 MySQL 开发库Ubuntu 下需要先sudo apt-get install libmysqlclient-dev python3-devWindows 下一般直接 pip 安装就能成功。pandas和numpy是用来处理评分矩阵的协同过滤计算相似度的时候会用到。scikit-learn提供了余弦相似度和皮尔逊相关系数的现成实现不用自己手写公式减少出错概率。2.2 settings.py 里必须改的四个配置项Django 默认用 SQLite要换成 MySQL 得改settings.py里的DATABASES配置。同时因为前端模板和静态文件要正常加载TEMPLATES和STATIC相关配置也得调整。下面是我一般会改的四个地方# movie_system/settings.py # 1. 注册应用 INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, recommend, # 新增 ] # 2. 数据库配置 DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: movie_db, # 数据库名需要提前在 MySQL 里创建 USER: root, # 你的 MySQL 用户名 PASSWORD: your_password, # 你的 MySQL 密码 HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4, }, } } # 3. 模板路径 TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [BASE_DIR / templates], # 新增模板目录 APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ] # 4. 静态文件与媒体文件 STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR / static] MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / media # 中文支持 LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ FalseDATABASES里的NAME对应的数据库必须提前在 MySQL 里用CREATE DATABASE movie_db CHARACTER SET utf8mb4;创建好Django 的migrate命令只建表不建库。OPTIONS里的utf8mb4是为了支持中文和特殊字符用utf8在某些场景下会出问题。USE_TZ False配合TIME_ZONE设置能让后台显示的时间就是北京时间不然默认 UTC 时间会让你在调试时怀疑人生。2.3 建表与数据迁移从文档里的表结构到 Django Model文档里给了电影资讯表、电影信息表、电影信息评论表的结构我一般会把这些字段直接翻译成 Django 的 Model 类。下面以电影信息表和评论表为例展示怎么把文档里的表格变成可执行的代码# recommend/models.py from django.db import models from django.contrib.auth.models import User class Movie(models.Model): 电影信息表对应文档中的电影信息表结构 name models.CharField(max_length200, verbose_name电影名称) category models.CharField(max_length100, verbose_name电影类型) director models.CharField(max_length100, verbose_name导演) actors models.CharField(max_length500, verbose_name主演) region models.CharField(max_length100, verbose_name制片地区) release_date models.DateField(verbose_name上映日期) description models.TextField(verbose_name电影描述) poster models.ImageField(upload_toposters/, verbose_name电影海报) video_url models.CharField(max_length500, blankTrue, verbose_name电影视频) thumbs_up models.IntegerField(default0, verbose_name赞) thumbs_down models.IntegerField(default0, verbose_name踩) click_time models.DateTimeField(auto_nowTrue, verbose_name最近点击时间) created_at models.DateTimeField(auto_now_addTrue, verbose_name创建时间) class Meta: db_table movie_info verbose_name 电影信息 class Rating(models.Model): 电影评分表协同过滤的核心数据来源 user models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name用户) movie models.ForeignKey(Movie, on_deletemodels.CASCADE, verbose_name电影) score models.FloatField(verbose_name评分) # 1-5 分 comment models.TextField(blankTrue, verbose_name评论) created_at models.DateTimeField(auto_now_addTrue, verbose_name评分时间) class Meta: db_table movie_rating unique_together (user, movie) # 同一用户对同一电影只能评一次 verbose_name 电影评分unique_together这个约束很重要它保证了评分矩阵里不会出现同一个用户对同一部电影有两条评分记录否则计算相似度的时候会出问题。score用FloatField而不是IntegerField是为了后续如果要做归一化或者加权计算时保留小数精度。on_deletemodels.CASCADE表示用户或电影被删除时对应的评分记录也一起删掉避免脏数据。模型写完之后执行迁移命令# 生成迁移文件 python manage.py makemigrations recommend # 执行迁移在 MySQL 中建表 python manage.py migrate # 创建超级管理员用于登录 Django Admin 后台 python manage.py createsuperusermakemigrations会根据 Model 定义生成 SQL 语句migrate才会真正在 MySQL 里执行。如果这一步报错说无法连接数据库先检查 MySQL 服务是否启动、用户名密码是否正确、数据库是否已创建。createsuperuser创建的账号可以登录/admin后台文档里说的「管理员功能」其实大部分可以直接用 Django Admin 实现不需要自己写管理界面。3. 协同过滤推荐算法的落地从评分矩阵到推荐列表3.1 用户基于与物品基于选哪种为什么协同过滤分两大流派UserCF 和 ItemCF。UserCF 是找和你口味相似的人把他们喜欢的电影推荐给你ItemCF 是找你喜欢的电影相似的电影推荐给你。在电影推荐场景下ItemCF 通常更稳定因为电影的数量和属性相对固定而用户的口味会随时间变化。文档里没有明确说用哪种但从「电影评分管理」这个功能来看评分数据是核心我一般会优先实现 ItemCF然后用 UserCF 做对比实验答辩的时候两个都讲显得工作量更饱满。ItemCF 的核心步骤就三步计算物品之间的相似度、根据用户历史评分找相似物品、加权打分生成推荐列表。相似度计算用余弦相似度或者皮尔逊相关系数前者适合评分数据稠密的情况后者对评分尺度差异更鲁棒。下面是一个完整的 ItemCF 实现# recommend/cf_algorithm.py import numpy as np import pandas as pd from sklearn.metrics.pairwise import cosine_similarity from .models import Rating, Movie def build_rating_matrix(): 从数据库构建用户-电影评分矩阵 ratings Rating.objects.all().values(user_id, movie_id, score) df pd.DataFrame(list(ratings)) if df.empty: return None, None, None # 透视表行是用户列是电影值是评分 matrix df.pivot_table( indexuser_id, columnsmovie_id, valuesscore, fill_value0 # 未评分的填 0 ) return matrix, matrix.index.tolist(), matrix.columns.tolist() def item_similarity(matrix): 计算物品之间的余弦相似度 # 转置后行是电影列是用户 item_matrix matrix.T.values # 余弦相似度矩阵shape 为 (电影数, 电影数) sim cosine_similarity(item_matrix) # 对角线置 0避免自己和自己相似度为 1 影响推荐 np.fill_diagonal(sim, 0) return sim def recommend_for_user(user_id, matrix, sim, top_n10): 为指定用户生成推荐列表 if user_id not in matrix.index: return [] user_idx matrix.index.get_loc(user_id) user_ratings matrix.iloc[user_idx].values # 该用户对所有电影的评分 # 只考虑用户评过分的电影 rated_indices np.where(user_ratings 0)[0] if len(rated_indices) 0: return [] # 加权求和相似度 * 用户评分 scores np.zeros(matrix.shape[1]) for idx in rated_indices: scores sim[idx] * user_ratings[idx] # 过滤掉用户已经评过分的电影 scores[rated_indices] 0 # 取 top_n top_indices np.argsort(scores)[::-1][:top_n] movie_ids [matrix.columns[i] for i in top_indices if scores[i] 0] # 返回电影对象列表 return list(Movie.objects.filter(id__inmovie_ids))build_rating_matrix用 pandas 的pivot_table把数据库里的评分记录转成矩阵fill_value0表示未评分用 0 填充这样余弦相似度计算时不会因为缺失值报错。item_similarity里np.fill_diagonal(sim, 0)这行很关键如果不置零推荐结果里会出现用户已经评过分的电影自己推荐给自己。recommend_for_user里的加权求和逻辑是 ItemCF 的标准做法用户对某部电影的评分乘以该电影与候选电影的相似度累加后排序。scores[rated_indices] 0确保已评分的电影不会被重复推荐。3.2 把推荐结果接入 Django 视图和模板算法写好了得让它在页面上跑起来。我一般会在views.py里写一个推荐视图然后在用户首页调用。下面是一个简化的实现# recommend/views.py from django.shortcuts import render from django.contrib.auth.decorators import login_required from .cf_algorithm import build_rating_matrix, item_similarity, recommend_for_user from .models import Movie login_required def home(request): 用户首页展示推荐电影和最新电影 matrix, user_ids, movie_ids build_rating_matrix() recommended [] if matrix is not None and request.user.id in user_ids: sim item_similarity(matrix) recommended recommend_for_user(request.user.id, matrix, sim, top_n8) # 如果推荐为空新用户没有评分记录展示热门电影 if not recommended: recommended list(Movie.objects.order_by(-thumbs_up)[:8]) latest Movie.objects.order_by(-created_at)[:8] return render(request, home.html, { recommended: recommended, latest: latest, })login_required装饰器保证只有登录用户才能看到个性化推荐未登录用户跳转到登录页。build_rating_matrix每次请求都重新构建矩阵在数据量小的时候没问题但如果评分数据上万条这个查询会变慢后面进阶章节会讲怎么优化。新用户没有评分记录时recommend_for_user返回空列表这时候用thumbs_up排序展示热门电影作为兜底避免首页空白。模板部分用 Django 的模板语法循环渲染即可!-- templates/home.html -- {% extends base.html %} {% block content %} div classrecommend-section h3为你推荐/h3 div classmovie-grid {% for movie in recommended %} div classmovie-card img src{{ movie.poster.url }} alt{{ movie.name }} h4{{ movie.name }}/h4 p{{ movie.category }} | {{ movie.director }}/p a href{% url movie_detail movie.id %}查看详情/a /div {% empty %} p暂无推荐请先给一些电影评分/p {% endfor %} /div /div {% endblock %}{% empty %}是 Django 模板里处理空列表的语法比用{% if %}判断更简洁。movie.poster.url要求ImageField配置了MEDIA_URL和MEDIA_ROOT并且在urls.py里加了静态文件服务否则图片显示不出来。3.3 评分数据的冷启动与推荐效果验证新用户注册进来没有任何评分协同过滤算不出相似度这是推荐系统经典的冷启动问题。文档里没有提解决方案但实际做毕设的时候老师很可能会问。我一般会做两件事一是新用户首次登录时弹出一个「选几部你看过的电影打个分」的引导页快速收集初始评分二是用热门电影和最新电影做兜底推荐保证首页不空。引导页的实现就是在用户注册成功后跳转到一个电影列表页让用户勾选并打分提交后写入 Rating 表。验证推荐效果可以用离线实验把评分数据按 8:2 分成训练集和测试集用训练集算相似度在测试集上预测评分计算 RMSE 或 MAE。如果 RMSE 在 0.8 到 1.2 之间说明推荐效果还可以接受。这个实验不需要在系统里做单独写个脚本跑一下把结果写进论文的「系统测试」章节就行。4. 避坑与排查那些文档里不会写的翻车现场4.1 MySQL 8.0 认证插件导致 Django 连接失败现象migrate的时候报django.db.utils.OperationalError: (1045, Access denied for user rootlocalhost)但密码明明是对的。原因MySQL 8.0 默认用caching_sha2_password认证插件而mysqlclient在某些版本下不兼容这种认证方式。解决登录 MySQL 后执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password;然后FLUSH PRIVILEGES;。或者升级mysqlclient到 2.2.0 以上版本新版本已经支持caching_sha2_password。4.2 评分矩阵稀疏导致相似度计算全为 0现象推荐结果为空或者推荐出来的电影明显不相关。原因用户评分数据太少矩阵里大部分是 0余弦相似度计算出来接近 0排序后没有有效推荐。解决设置一个相似度阈值比如只保留相似度大于 0.1 的邻居同时增加兜底策略推荐列表为空时返回热门电影。另外可以在论文里说明这是冷启动问题并给出你的解决方案反而是加分项。4.3 中文乱码数据库、Django、模板三处都要设对现象电影名称显示成??????或者是影。原因MySQL 数据库字符集不是utf8mb4或者 Django 的OPTIONS里没设charset或者模板文件没保存为 UTF-8。解决建库时用CREATE DATABASE movie_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;settings.py的DATABASES里加OPTIONS: {charset: utf8mb4}模板文件用编辑器保存为 UTF-8 无 BOM 格式。三处都对了才不会乱码。4.4 图片上传后前端显示 404现象后台上传了电影海报前端img标签的src路径正确但图片加载不出来。原因Django 开发环境下MEDIA_URL的文件不会自动由 Django 服务需要在urls.py里手动配置。解决在项目根urls.py里加from django.conf import settings和from django.conf.urls.static import static然后在urlpatterns末尾加 static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)。注意这个只在DEBUGTrue时有效生产环境需要用 Nginx 之类的服务器来处理静态文件。4.5 协同过滤计算超时每次请求都重算相似度矩阵现象首页加载越来越慢评分数据到几千条的时候要等好几秒。原因home视图里每次请求都调用build_rating_matrix和item_similarity这两个操作都是 O(n²) 复杂度数据量上来之后扛不住。解决把相似度矩阵缓存起来用 Django 的cache框架或者直接存到文件里设置一个合理的过期时间比如 1 小时。评分数据变化不频繁的话甚至可以写一个管理命令手动触发重算。具体做法在下一章展开。5. 进阶技巧缓存相似度矩阵与用管理命令批量重算5.1 用 Django Cache 把相似度矩阵缓存到内存上一章提到每次请求重算相似度矩阵会拖慢响应最直接的优化就是用缓存。Django 自带缓存框架开发环境用本地内存缓存就够了生产环境可以换 Redis。配置和改造代码如下# movie_system/settings.py CACHES { default: { BACKEND: django.core.cache.backends.locmem.LocMemCache, LOCATION: movie-sim-cache, TIMEOUT: 3600, # 1 小时过期 } }# recommend/cf_algorithm.py from django.core.cache import cache import hashlib def get_cached_similarity(): 带缓存的相似度矩阵获取 # 用评分记录数作为缓存 key 的一部分数据变了 key 就变 rating_count Rating.objects.count() cache_key fitem_sim_{hashlib.md5(str(rating_count).encode()).hexdigest()[:8]} sim cache.get(cache_key) if sim is None: matrix, user_ids, movie_ids build_rating_matrix() if matrix is None: return None, None, None sim item_similarity(matrix) # 缓存相似度矩阵和对应的 movie_ids cache.set(cache_key, (sim, movie_ids), 3600) else: sim, movie_ids sim matrix, user_ids, _ build_rating_matrix() return matrix, sim, movie_ids缓存 key 里带上评分记录数这样有新评分写入时 key 会变化自动触发重算不需要手动清缓存。cache.set的第三个参数是过期时间单位秒。LocMemCache是进程内缓存多进程部署时每个进程有独立的缓存生产环境建议换django-redis。5.2 写一个管理命令批量重算并导出推荐结果如果不想在请求时算可以写一个 Django 管理命令手动或定时执行把推荐结果预先算好存到数据库或文件里。这样前端只需要读结果响应速度极快。# recommend/management/commands/refresh_recommendations.py from django.core.management.base import BaseCommand from django.contrib.auth.models import User from recommend.cf_algorithm import build_rating_matrix, item_similarity, recommend_for_user import json class Command(BaseCommand): help 批量重算所有用户的推荐结果并保存到文件 def handle(self, *args, **options): matrix, user_ids, movie_ids build_rating_matrix() if matrix is None: self.stdout.write(暂无评分数据跳过) return sim item_similarity(matrix) result {} for user in User.objects.all(): if user.id in user_ids: movies recommend_for_user(user.id, matrix, sim, top_n10) result[user.id] [m.id for m in movies] else: result[user.id] [] with open(recommendations.json, w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) self.stdout.write(f已为 {len(result)} 个用户生成推荐结果)执行python manage.py refresh_recommendations就会在项目根目录生成recommendations.json。前端视图改成读这个文件速度从秒级降到毫秒级。这个命令可以配合系统的定时任务比如每天凌晨跑一次。5.3 答辩时怎么讲清楚「协同过滤」不是调包很多同学担心老师问「你这算法是自己写的还是调库的」。我的经验是坦诚说相似度计算用了sklearn的cosine_similarity但整个推荐流程——从数据库取评分、构建矩阵、过滤已评分、加权排序、返回结果——都是自己实现的。然后可以现场打开cf_algorithm.py指着recommend_for_user函数讲加权求和的逻辑再打开models.py讲评分表的设计和unique_together约束。老师一般不会刁难反而会觉得你对代码有掌控力。从那以后我每次拿到这类毕设项目都会先把settings.py和models.py过一遍确认数据库配置和表结构没问题再跑migrate和createsuperuser最后才去调算法。这个顺序能帮你省下大量排查环境问题的时间。希望帮到你。本文还有配套的精品资源点击获取