简介这是一套面向高校学生与Python初学者的酒店推荐系统毕业设计完整源码包采用Django框架搭建前后端配套数据库脚本与项目文档可直接用于毕业设计、课程设计或Web开发练手。系统区分管理员与用户两类角色管理员可管理用户、客房类型、酒店客房、客房预定、入住登记、续订、退房、留言反馈及系统资料用户则可完成客房浏览预定、入住登记、续订与退房等操作覆盖酒店业务全流程。压缩包共597个文件约33.83MB包含56个py后端源码、118个vue前端组件、63个js脚本、43个png与53个jpg界面素材以及sql建库脚本、bat启动脚本和doc说明文档前后端结构清晰。目前已有63人学习下载适合需要完整项目参考、快速理解Django与Vue协作方式并完成答辩准备的读者。1. 酒店推荐系统毕设从一份前后端源码能跑出什么很多同学拿到「酒店推荐系统完整前后端源码LW」这类压缩包时第一反应是解压、找README、装依赖、跑起来然后截图交差。但真正决定这份毕设能不能过答辩、能不能在简历上写一笔的不是它能不能跑而是你能不能讲清楚推荐逻辑是怎么算出来的、前后端数据怎么流转、以及为什么用协同过滤而不是简单按价格排序。这篇笔记就围绕这套 Python 前后端源码把环境搭建、推荐算法复现、接口联调、避坑排查和进阶改造讲透适合正在做计算机毕业设计、想拿一套能讲明白的推荐系统交差的同学。整套方案的核心技术栈通常是 Flask/Django 做后端、Vue 或原生 HTML 做前端、MySQL 存数据、协同过滤做推荐下面按落地顺序拆开讲。2. 环境搭建与源码结构把 Python 前后端跑起来的第一公里2.1 先看清目录结构再动手装依赖拿到压缩包后不要急着pip install先花五分钟把目录结构摸清楚。典型的酒店推荐系统源码会分成后端服务、前端页面、数据库脚本、算法模块四块结构大致如下hotel-recommend/ ├── backend/ # 后端服务 │ ├── app.py # Flask/Django 入口 │ ├── models.py # 数据模型酒店、用户、订单、评分 │ ├── recommend.py # 推荐算法核心 │ ├── requirements.txt # Python 依赖清单 │ └── config.py # 数据库连接配置 ├── frontend/ # 前端页面 │ ├── index.html # 首页/推荐列表 │ ├── detail.html # 酒店详情 │ └── static/ # css/js/图片 ├── sql/ │ └── hotel.sql # 建表 初始数据 └── README.md先确认requirements.txt里锁定的 Python 版本常见是 3.8 或 3.9。如果你本机装的是 3.12某些老依赖比如旧版pandas、numpy会编译失败这时候用虚拟环境隔离最稳妥。我一般会先建一个干净的虚拟环境避免污染全局包# 创建并激活虚拟环境隔离项目依赖 python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate # 安装依赖建议加国内镜像加速 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里的关键参数是-i指定镜像源能显著减少下载超时。如果requirements.txt里没有锁版本号装出来的可能是最新版接口不兼容的概率会上升遇到报错优先怀疑版本问题。2.2 数据库导入与连接配置后端跑不起来八成卡在数据库。先用 MySQL 建库再导入sql/hotel.sql# 登录 MySQL 后建库 mysql -u root -p CREATE DATABASE hotel_db DEFAULT CHARSET utf8mb4; exit # 导入建表脚本和初始数据 mysql -u root -p hotel_db sql/hotel.sql导入完成后打开config.py或app.py里的数据库配置段把用户名、密码、库名改成你本机的# config.py 数据库配置示例 DB_CONFIG { host: 127.0.0.1, port: 3306, user: root, password: 你的密码, # 改成自己的 database: hotel_db, charset: utf8mb4 }charset一定要用utf8mb4否则酒店名称里的生僻字或 emoji 会乱码。改完配置先别启动服务用一段最小脚本测一下连接是否通import pymysql from config import DB_CONFIG conn pymysql.connect(**DB_CONFIG) cursor conn.cursor() cursor.execute(SELECT COUNT(*) FROM hotel) print(酒店总数:, cursor.fetchone()[0]) conn.close()能打印出酒店数量说明数据库这一环通了。这一步是后面所有推荐逻辑的地基地基不稳后面调接口全是玄学报错。2.3 启动后端与前端联调数据库通了之后启动后端服务# 进入后端目录启动 Flask cd backend python app.py # 默认跑在 http://127.0.0.1:5000前端如果是纯静态页面直接用浏览器打开index.html往往会出现跨域问题因为页面请求的是127.0.0.1:5000的接口。常见做法是用 Flask 自带的静态目录托管或者起一个简单的静态服务器# 在 frontend 目录起静态服务 python -m http.server 8080然后访问http://127.0.0.1:8080。如果页面能加载但列表为空打开浏览器 F12 看 Network 面板重点看接口返回的 JSON 结构和你前端解析的字段名是否对得上。字段名大小写不一致、返回是data.list而前端读的是data.rows这类问题在毕设源码里非常常见。3. 推荐算法复现协同过滤到底怎么算出推荐列表3.1 用户-酒店评分矩阵怎么构建推荐系统的核心是一张评分矩阵行是用户列是酒店格子里是评分。酒店推荐系统里评分来源通常是订单完成后的打分或者浏览、收藏行为折算的隐式评分。构建矩阵的代码一般长这样import pandas as pd import pymysql from config import DB_CONFIG # 从数据库拉取用户对酒店的评分记录 conn pymysql.connect(**DB_CONFIG) sql SELECT user_id, hotel_id, score FROM rating df pd.read_sql(sql, conn) conn.close() # 构建用户-酒店评分矩阵缺失值填 0 matrix df.pivot_table(indexuser_id, columnshotel_id, valuesscore).fillna(0) print(矩阵形状:, matrix.shape) # (用户数, 酒店数)pivot_table把长表转成宽表fillna(0)表示没评过分的当作 0。这里有个坑如果酒店数量上千、用户数量也上千矩阵会非常稀疏直接算相似度又慢又占内存。常见做法是只保留有评分的记录或者用稀疏矩阵存储。3.2 基于物品的协同过滤计算相似度酒店推荐里更常用的是基于物品item-based的协同过滤因为酒店数量相对稳定用户数量会不断增长。核心是算酒店之间的相似度from sklearn.metrics.pairwise import cosine_similarity # 转置后按酒店算相似度每行是一个酒店每列是一个用户 item_sim cosine_similarity(matrix.T) item_sim_df pd.DataFrame(item_sim, indexmatrix.columns, columnsmatrix.columns) def recommend_by_item(user_id, top_n10): # 取出该用户评过分的酒店 user_ratings matrix.loc[user_id] rated user_ratings[user_ratings 0].index.tolist() scores {} for hotel in rated: # 遍历该酒店相似的其它酒店按相似度加权累加 sim_hotels item_sim_df[hotel].sort_values(ascendingFalse)[1:20] for sim_hotel, sim in sim_hotels.items(): if sim_hotel not in rated: scores[sim_hotel] scores.get(sim_hotel, 0) sim * user_ratings[hotel] # 按得分排序取前 N 个 return sorted(scores.items(), keylambda x: x[1], reverseTrue)[:top_n]cosine_similarity算的是余弦相似度取值 0 到 1越接近 1 说明两家酒店被同一批用户喜欢的程度越像。top_n控制返回条数[1:20]是取最相似的 20 家候选这两个参数直接影响推荐结果的多样性和准确度。相似度阈值设太高推荐结果会集中在少数几家设太低又会推出一堆不相关的酒店。3.3 冷启动与推荐结果落库新用户没有评分记录协同过滤直接失效这就是冷启动。毕设里常见的兜底策略是新用户默认推荐评分最高的热门酒店或者按用户注册时填的城市、价格偏好做规则过滤。def recommend_with_fallback(user_id, top_n10): try: result recommend_by_item(user_id, top_n) if not result: raise ValueError(无推荐结果) return result except (KeyError, ValueError): # 冷启动兜底返回综合评分最高的酒店 conn pymysql.connect(**DB_CONFIG) sql SELECT hotel_id, AVG(score) AS avg_score FROM rating GROUP BY hotel_id ORDER BY avg_score DESC LIMIT %s df pd.read_sql(sql, conn, params[top_n]) conn.close() return list(zip(df[hotel_id], df[avg_score]))把推荐结果提前算好写进recommend_result表前端直接查表能避免每次请求都重算相似度。离线计算 在线查询是推荐系统最常见的落地方式答辩时能讲清楚这一点比只贴一段算法代码加分得多。4. 接口联调与前后端数据打通推荐列表怎么送到页面4.1 后端推荐接口设计前端要拿到推荐列表后端得暴露一个干净的接口。用 Flask 写一个返回 JSON 的路由from flask import Flask, request, jsonify from recommend import recommend_with_fallback app Flask(__name__) app.route(/api/recommend, methods[GET]) def api_recommend(): user_id request.args.get(user_id, typeint) top_n request.args.get(top_n, default10, typeint) if not user_id: return jsonify({code: 400, msg: 缺少 user_id}), 400 result recommend_with_fallback(user_id, top_n) # 把 hotel_id 和得分组装成前端需要的结构 data [{hotel_id: hid, score: round(float(score), 2)} for hid, score in result] return jsonify({code: 200, msg: success, data: data})接口返回统一用code/msg/data三段式前端处理起来最省心。user_id用typeint做参数校验避免前端传字符串导致查询报错。top_n给了默认值 10前端不传也能正常返回。4.2 前端请求与渲染前端拿到hotel_id列表后还需要补全酒店名称、图片、价格等信息。两种做法一是后端接口直接联表返回完整信息二是前端拿到 id 后再请求详情。毕设里为了减少请求次数通常在后端一次查完# 在接口里联表补全酒店信息 hotel_ids [item[hotel_id] for item in data] placeholders ,.join([%s] * len(hotel_ids)) sql fSELECT id, name, price, image FROM hotel WHERE id IN ({placeholders}) # 执行查询后按 id 合并到 data 中返回前端用fetch请求并渲染fetch(http://127.0.0.1:5000/api/recommend?user_id${userId}top_n10) .then(res res.json()) .then(res { if (res.code 200) { const list res.data; // 遍历渲染到推荐列表容器 document.querySelector(#recommend-list).innerHTML list .map(h div classcardh3${h.name}/h3p${h.price}/p/div) .join(); } }) .catch(err console.error(推荐接口请求失败:, err));fetch后面的.catch一定要写否则接口挂了页面白屏你连报错都看不到。渲染时注意对酒店名称做转义虽然毕设数据一般安全但养成习惯没坏处。4.3 跨域与登录态处理前后端分离最容易翻车的就是跨域。如果前端跑在 8080、后端跑在 5000浏览器会拦截请求。Flask 里装flask-cors一行解决from flask_cors import CORS app Flask(__name__) CORS(app, supports_credentialsTrue) # 允许跨域并携带 cookiesupports_credentialsTrue是为了让登录态能通过 cookie 传递。如果你的系统用 token 而不是 session那前端每次请求要在 header 里带上Authorization后端对应做校验。登录态没打通推荐接口拿不到user_id返回的就永远是冷启动的热门列表看起来「推荐不准」其实是身份没传过去。5. 避坑排查这套源码最容易翻车的五个地方5.1 现象pip 安装依赖报编译错误原因requirements.txt里的numpy、pandas版本太老和你本机 Python 版本不匹配或者缺少 C 编译环境。 解决先确认 Python 版本3.8/3.9 兼容性最好Windows 上装Microsoft C Build Tools实在装不上就手动指定较新的兼容版本比如pip install numpy1.24.3。5.2 现象数据库连不上报 Access denied原因config.py里的密码没改或者 MySQL 8 的认证插件和pymysql不兼容。 解决确认密码正确后如果报caching_sha2_password相关错误执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;再刷新权限。5.3 现象推荐结果每次刷新都不一样原因相似度计算里用了随机采样或者推荐结果没有落库、每次实时计算时数据顺序不稳定。 解决固定随机种子random.seed(42)排序时用sorted保证稳定更彻底的做法是把推荐结果离线算好写进表在线只查表。5.4 现象前端列表空白但接口返回 200原因前端解析的字段名和后端返回的不一致比如后端返回hotel_id前端读的是hotelId。 解决F12 打开 Network 看真实返回结构逐字段核对建议后端字段用下划线、前端统一转换别混用驼峰。5.5 现象酒店图片全部加载失败原因数据库里存的是本地绝对路径换台机器路径就失效。 解决图片统一放static/images下数据库只存文件名前端拼接相对路径访问。这是毕设源码里最典型的「换机即挂」问题。6. 从能跑到能讲把推荐系统改造成答辩加分项把源码跑通只是及格线真正让答辩老师点头的是你能说清楚「为什么这么设计」。我一般会做两件事一是加一个离线评估脚本用准确率或召回率证明推荐有效二是把算法模块解耦方便替换成别的策略做对比。先看评估脚本用留一法简单验证import numpy as np def evaluate(matrix, recommend_func, test_ratio0.2): hits, total 0, 0 for user_id in matrix.index: rated matrix.loc[user_id] rated_hotels rated[rated 0].index.tolist() if len(rated_hotels) 2: continue # 留一法藏起一个已评分酒店作为测试 test_hotel rated_hotels[-1] recs [h for h, _ in recommend_func(user_id, top_n10)] total 1 if test_hotel in recs: hits 1 return hits / total if total else 0 # 打印命中率答辩时作为推荐效果的量化依据 print(命中率:, evaluate(matrix, recommend_by_item))test_ratio控制测试集比例top_n要和线上推荐条数一致否则评估结果没有参考意义。命中率能到 0.2 以上在毕设场景里就算能交代了。再进一步可以把协同过滤和基于内容的推荐做对比。基于内容的推荐用酒店的价格、星级、位置做特征算用户偏好向量和酒店特征向量的相似度。两种策略各跑一遍评估用表格对比推荐策略命中率优点缺点基于物品协同过滤0.22利用群体行为准确度较高冷启动差稀疏矩阵慢基于内容推荐0.15新用户可用可解释性强依赖特征质量多样性差热门兜底0.08实现简单永不空结果个性化几乎为零这张表往答辩 PPT 一放你对推荐系统的理解深度立刻和只跑通源码的同学拉开差距。老师问「为什么用协同过滤」你可以答「因为酒店数据有天然的用户评分行为item-based 比 user-based 更稳定且我做了冷启动兜底和离线评估验证」。最后说个血泪经验毕设代码一定要自己从头到尾跑一遍别直接拿压缩包里的截图当运行证据。我见过太多同学源码没跑通就写论文答辩现场被要求演示结果数据库连不上、依赖没装、接口 500场面非常被动。把环境、数据、算法、接口四块各自跑通并留下自己的运行记录这份毕设才算真正属于你。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?