news 2026/10/18 12:55:09

Django旅游推荐系统毕设实战:协同过滤算法与MySQL部署避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django旅游推荐系统毕设实战:协同过滤算法与MySQL部署避坑指南

简介:这是一套面向计算机相关专业毕设学生与Python项目实战学习者的旅游推荐数据分析可视化系统,采用python+Django+mysql技术栈,并引入协同过滤算法实现个性化推荐,可直接作为毕业设计、课程设计或期末大作业使用。压缩包共422个文件,约9.36MB,以174个js、59个css、40个json、27个py、18个html等为主,涵盖前端页面样式、后端业务逻辑、数据配置与静态资源,另附sql数据库脚本、docx部署说明及md文档,结构完整便于二次开发。系统分为用户与管理员两端:用户可完成登录注册、个人信息管理、景区浏览、评分收藏与智能推荐;管理员可对景区信息、景区类型分类及用户资料进行增删改查与行为记录管理。项目经过严格调试,确保可运行,已有135人学习下载,适合需要完整源码、数据库与部署文档的读者快速搭建环境、理解推荐算法落地流程并完成毕设交付。

1. 旅游推荐系统拆包:一份能跑通的 Django 毕设长什么样

很多做毕设的同学都遇到过这种局面:选题定了“旅游推荐数据分析可视化”,网上搜到的源码包要么跑不起来,要么只有一堆前端 CSS 文件,后端逻辑和数据库全是空的。我最近拆了一个 Python 项目实战包,标题是旅游推荐数据分析可视化,技术栈是 python + Django + mysql + 协同过滤算法,压缩包里带了源码、数据库和部署说明。打开一看,前端样式文件确实不少——bootstrap.css、bootstrap.rtl.css、bootstrap.min.css、remixicon.css、boxicons.css、bootstrap-icons.css、skin.css、bootstrap-grid.rtl.css 这些都在,说明界面层是认真搭过的,不是随便糊一个页面。这个包适合两类人:一类是计算机相关专业正在做毕设、需要一套完整可运行系统的学生;另一类是想拿一个真实 Django 项目练手、把协同过滤从公式落到代码里的 Python 学习者。它解决的核心问题不是“教你 Django 语法”,而是给你一套已经调通的骨架,让你把精力放在理解推荐逻辑和改造成自己课题上。

2. 环境搭建与数据库导入:从解压到登录后台

2.1 依赖清单与版本选择

拿到压缩包后,第一件事不是急着python manage.py runserver,而是先确认 Python 版本和依赖。Django 项目对版本比较敏感,尤其是涉及 mysqlclient 和协同过滤里用到的 numpy 时。我一般会先建一个独立虚拟环境,避免和系统里其他包打架。

# 创建虚拟环境,python 版本建议 3.8 到 3.10 python -m venv venv # 激活虚拟环境 # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate # 安装核心依赖,版本按部署说明里的 requirements 为准 pip install django mysqlclient numpy pandas

这里有几个参数要留意。mysqlclient是 Django 连接 MySQL 最常用的驱动,比 pymysql 性能好,但在 Windows 上编译需要本地有 MySQL 开发库,装不上时可以临时换pymysql并在__init__.py里做兼容。numpy和pandas不是 Django 本身需要的,而是协同过滤计算相似度矩阵时会用到,如果部署说明里没列,也要提前装上,否则推荐模块一跑就报ModuleNotFoundError。

2.2 数据库配置与导入

项目用的是 MySQL,部署说明里一般会给一个.sql文件。常见做法是先在 MySQL 里建一个空库,字符集用utf8mb4,然后导入数据。

-- 建库,字符集必须用 utf8mb4,否则中文景区名会乱码 CREATE DATABASE travel_recommend DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 导入数据,在命令行执行 -- mysql -u root -p travel_recommend < travel_recommend.sql

导入完成后,打开 Django 的settings.py,找到DATABASES配置段,把 NAME、USER、PASSWORD、HOST、PORT 改成你本地的。这里有个容易翻车的点:如果.sql文件里已经建了库,你再手动建一次会冲突,导入前先确认文件头部有没有CREATE DATABASE语句。另外,Django 的migrate命令和直接导入.sql是两条路,如果.sql里已经包含全部表结构和数据,就不需要再执行migrate,否则可能报表已存在。

# settings.py 数据库配置示例 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'travel_recommend', # 数据库名 'USER': 'root', # 你的 MySQL 用户名 'PASSWORD': 'your_password', # 你的密码 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': {'charset': 'utf8mb4'}, # 防止中文乱码 } }

配置改完后,执行python manage.py runserver,浏览器打开127.0.0.1:8000,能看到登录页就说明环境通了。管理员账号一般在.sql里已经预置,或者用python manage.py createsuperuser新建一个,登录后台就能看到景区管理、用户管理这些入口。

3. 协同过滤推荐模块:用户评分数据怎么变成推荐列表

3.1 协同过滤在旅游场景里的选型理由

旅游推荐和电商推荐有个明显区别:用户对景区的评分行为比买东西稀疏得多。一个人可能一年只去几个地方,评分矩阵非常空。项目用的是协同过滤算法,具体来说是基于用户的协同过滤(UserCF)或基于物品的协同过滤(ItemCF),两者在这个场景下各有取舍。

UserCF 的思路是“找和你口味相似的人,把他们去过但你没去过的景区推给你”。优点是能发现跨类型的惊喜推荐,缺点是用户数量一多,相似度矩阵计算量会爆炸。ItemCF 的思路是“你给某个景区打了高分,找和它相似的景区推给你”,优点是物品数量通常比用户少,矩阵更稳定,缺点是推荐结果容易局限在同一类型里。这个项目里景区数量是可控的,ItemCF 更常见,但具体用哪种要看源码里recommend模块的实现。

3.2 评分矩阵构建与相似度计算

协同过滤的核心是把用户-景区评分表转成矩阵,然后算相似度。下面这段代码是我根据这类项目常见写法还原的,逻辑是:先查出所有评分记录,构建用户-物品矩阵,再用余弦相似度算景区之间的相似度。

import numpy as np from django.db.models import Q from .models import Rating, ScenicSpot def build_similarity_matrix(): """构建景区相似度矩阵,基于用户评分""" # 取出所有评分记录 ratings = Rating.objects.all().values('user_id', 'spot_id', 'score') # 获取所有景区 id 和用户 id spot_ids = list(ScenicSpot.objects.values_list('id', flat=True)) user_ids = list(set(r['user_id'] for r in ratings)) # 建立 id 到索引的映射 spot_index = {sid: i for i, sid in enumerate(spot_ids)} user_index = {uid: i for i, uid in enumerate(user_ids)} # 初始化评分矩阵,行是用户,列是景区 matrix = np.zeros((len(user_ids), len(spot_ids))) for r in ratings: matrix[user_index[r['user_id']], spot_index[r['spot_id']]] = r['score'] # 计算景区之间的余弦相似度 # 对列向量做归一化,避免量纲影响 norm = np.linalg.norm(matrix, axis=0) norm[norm == 0] = 1 # 防止除零 normalized = matrix / norm similarity = np.dot(normalized.T, normalized) return spot_ids, similarity

这段代码有几个参数和边界要说明。matrix是用户数乘景区数的二维数组,实际项目里这个矩阵可能非常稀疏,大部分位置是 0。norm计算的是每个景区列向量的模长,归一化后再做点积,得到的就是余弦相似度,取值范围在 -1 到 1 之间,旅游评分通常是 1 到 5 的正数,所以相似度基本落在 0 到 1。norm[norm == 0] = 1这行是后悔药,防止某个景区没有任何评分时除零报错。相似度矩阵是对称矩阵,对角线是景区和自己的相似度,恒为 1,推荐时要把自己排除掉。

3.3 生成推荐列表与冷启动处理

拿到相似度矩阵后,推荐逻辑就是:对用户已评分的景区,找到最相似的 K 个景区,按相似度加权打分,取 TopN 返回。

def recommend_for_user(user_id, top_n=10, k=5): """给指定用户生成推荐列表""" spot_ids, similarity = build_similarity_matrix() spot_index = {sid: i for i, sid in enumerate(spot_ids)} # 用户已评分的景区 rated = Rating.objects.filter(user_id=user_id).values_list('spot_id', 'score') rated_dict = {r[0]: r[1] for r in rated} if not rated_dict: # 冷启动:没有评分记录时,返回评分最高的景区 return ScenicSpot.objects.order_by('-avg_score')[:top_n] scores = {} for spot_id, score in rated_dict.items(): if spot_id not in spot_index: continue idx = spot_index[spot_id] # 取相似度最高的 k 个景区 sim_row = similarity[idx] top_k_idx = np.argsort(sim_row)[::-1][1:k+1] # 跳过自己 for i in top_k_idx: candidate = spot_ids[i] if candidate in rated_dict: continue # 已经评过的不再推荐 scores[candidate] = scores.get(candidate, 0) + sim_row[i] * score # 按得分排序,取前 top_n sorted_spots = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_n] return ScenicSpot.objects.filter(id__in=[s[0] for s in sorted_spots])

top_n控制返回多少个推荐,k控制参考多少个相似景区,这两个参数直接决定推荐结果的多样性和准确度。k太小,推荐容易集中在少数几个热门景区;k太大,计算量上升且可能引入不相关的噪声。冷启动那段是很多毕设里被忽略的:新用户没有任何评分,协同过滤算不出来,常见做法是退化成热门推荐,按景区平均分排序。这个逻辑在答辩时经常被问到,提前想清楚能省不少事。

4. 避坑与排查:部署和运行中最容易翻车的五个点

4.1 中文乱码:景区名变成问号

现象是导入.sql后,后台看到的景区名称全是???或者乱码。原因通常是建库时字符集用了latin1或者utf8,而 MySQL 的utf8只支持三字节,存不下某些生僻字。解决办法是建库时强制utf8mb4,并且在 Django 的DATABASES里加OPTIONS: {'charset': 'utf8mb4'}。如果已经导入错了,需要重建库再导一次,改字符集不会自动修复已有数据。

4.2 静态文件 404:页面样式全丢

现象是登录页能打开,但 bootstrap 样式没生效,页面排版全乱。原因是 Django 在生产模式下不会自动托管静态文件,开发模式下需要确认settings.py里DEBUG = True,并且INSTALLED_APPS里有django.contrib.staticfiles。如果还是 404,检查STATIC_URL和STATICFILES_DIRS是否指向了正确的static目录。压缩包里那一堆bootstrap.css、remixicon.css、boxicons.css应该放在static/css/下,模板里用{% static 'css/bootstrap.css' %}引用。

4.3 协同过滤报 ModuleNotFoundError

现象是点开推荐页面直接 500,控制台提示No module named 'numpy'或pandas。原因是部署说明里只列了 Django 和 mysqlclient,没提科学计算库。解决办法是手动pip install numpy pandas。如果安装 numpy 时编译报错,可以换用预编译的 wheel 包,或者降级到和 Python 版本匹配的 numpy 版本。

4.4 数据库连接被拒绝

现象是runserver启动时报django.db.utils.OperationalError: (2003, "Can't connect to MySQL server")。原因通常是 MySQL 服务没启动,或者HOST填了localhost但 MySQL 只监听127.0.0.1,再或者端口不是默认的 3306。解决办法是先确认 MySQL 服务在运行,然后把HOST改成127.0.0.1,端口按实际配置填。如果用了 Docker 或者远程数据库,还要检查防火墙和用户权限。

4.5 推荐结果为空或重复

现象是推荐列表要么空白,要么反复推同一个景区。原因是相似度矩阵计算时没有排除用户已评分的景区,或者top_k_idx没有跳过自身。解决办法是在生成推荐时加判断if candidate in rated_dict: continue,并且在取相似景区时用[1:k+1]跳过索引 0 的自己。另外,如果某个景区评分人数太少,相似度会不稳定,可以在计算前过滤掉评分次数低于阈值的景区。

5. 从跑通到改出彩:把毕设做出差异化的三个技巧

5.1 给推荐结果加可解释性

答辩时老师最爱问的一句话是“你为什么推荐这个”。协同过滤本身是个黑匣子,但你可以把相似度分数和参考景区暴露出来。比如在推荐列表里加一列“因为你去过 XX 景区”,把sim_row[i]最高的那个已评分景区作为推荐理由。实现上就是在recommend_for_user里多存一个reason字段,返回时带上景区名。这个改动不大,但能让你的系统从“能跑”变成“能讲”。

5.2 用评分数量做加权

纯余弦相似度有个问题:两个景区如果都只有一条评分,且分数碰巧一样,相似度会算成 1,但这明显不可靠。常见做法是引入显著性加权,相似度乘以min(共同评分用户数, 阈值) / 阈值,共同评分用户越多,相似度越可信。这个公式在推荐系统里叫“显著性加权”,改起来就几行代码,但能明显减少冷门景区之间的虚假相似。

# 显著性加权示例,common_users 是共同评分用户数 threshold = 5 weight = min(common_users, threshold) / threshold similarity[i][j] = similarity[i][j] * weight

5.3 验证推荐效果的一个笨办法

没有真实用户日志的情况下,怎么证明你的推荐比“按平均分排序”好?我一般会做离线评估:把评分数据按 8:2 切成训练集和测试集,用训练集算相似度,对测试集里的用户生成推荐,看推荐列表里有多少景区是用户实际评过分的。这个指标叫命中率(Hit Rate),虽然粗糙,但比空口说“推荐效果不错”有说服力。具体做法是随机留出每个用户 20% 的评分不参与计算,然后看 Top10 推荐里命中几个。命中率能到 10% 以上,在毕设里就算能交代过去了。

从那以后我每次拿到这类源码包,都强制先跑一遍数据库导入和推荐接口,确认评分矩阵不是空的、相似度不是全零,再去看前端样式。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 12:54:58

URP Kawase模糊实现:轻量级后处理与RendererFeature集成

简介&#xff1a;这是一份面向Unity中高级开发者与URP渲染管线学习者的Kawase模糊后处理实验项目&#xff0c;聚焦于ScriptableRenderFeature在URP中的实践应用&#xff0c;解决自定义多Pass后处理效果开发难、调试门槛高的问题。资源共66个文件&#xff0c;含20个核心asset&am…

作者头像 李华
网站建设 2026/10/18 12:52:33

用C#拆解《麦田物语》:模拟经营游戏从源码到扩展玩法

简介&#xff1a;基于C#与Unity引擎开发的《麦田物语》模拟经营游戏完整源码&#xff0c;适合Unity初学者、游戏开发学习者及对模拟经营玩法感兴趣的开发者参考。项目包含完整的场景、脚本、动画与预制体资源&#xff0c;从资源描述中的脚本生命周期说明可以看出&#xff0c;源…

作者头像 李华
网站建设 2026/10/18 12:51:48

从 GIS 到 Spatial Agent:用 TaoToken 统一 Key 打通 MCP 的 AI 入口

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 12:51:05

Java数据结构课设实战:通讯录管理+24点穷举算法全解析

简介&#xff1a;这是一份面向高校计算机相关专业学生的数据结构课程设计资源&#xff0c;以Java语言实现两个经典实训项目&#xff1a;手机通讯录模拟与24点扑克牌游戏。前者利用ArrayList/LinkedList/HashMap等容器完成联系人的增删改查&#xff0c;后者通过递归、回溯、深度…

作者头像 李华
网站建设 2026/10/18 12:50:57

华为杯F题机组排班建模与求解:约束条件与易错点全解析

简介&#xff1a;2021年华为杯F题“航空公司机组优化排班问题”的完整解题思路与可运行代码&#xff0c;面向参加中国研究生数学建模竞赛的研究生。压缩包共16个文件&#xff0c;以Python脚本为主&#xff08;9个py&#xff09;&#xff0c;配套4个CSV数据文件、1个赛题Word说明…

作者头像 李华
网站建设 2026/10/18 12:49:53

RAM最大使用率监控方案:捕捉内存峰值与告警实战

1. 为什么盯着“最大使用率”而不是平均值——需求与场景做运维的时间长了&#xff0c;你会发现大部分监控面板上放的默认指标都是“平均内存使用率”&#xff0c;折线图看起来平平整整&#xff0c;好像一切尽在掌握。但真正出问题的时候&#xff0c;恰恰是那些“尖刺”撑爆了整…

作者头像 李华