本文将此前的 Java 控制台推荐系统项目重构为 Web 版,使用 Python + Flask 从零搭建一个可浏览器访问的“电视剧趣推系统”。项目不依赖数据库,采用纯内存数据模型,适合 Python 初学者和 Web 开发入门者学习。
系统包含电视剧展示、用户偏好记录、智能推荐三大核心功能。后端基于 Flask 实现路由控制与推荐逻辑,前端使用 Jinja2 模板引擎结合 Bootstrap 快速构建响应式页面,实现“喜欢”操作与个性化推荐。推荐策略采用“偏好类型匹配 + 高分优先”算法,为用户生成定制化内容。
文章提供完整项目结构、逐行代码解析、HTML 模板设计、运行教程及常见问题解决方案。项目结构清晰、注释详尽、扩展性强,支持后续接入 SQLite、用户登录、REST API 等进阶功能。
通过本项目,读者可掌握 Flask 基础开发流程、前后端数据传递、模板渲染、session 管理等核心技能,是 Python Web 入门的优质练手项目。
关键词:Python Flask、推荐系统、Web 开发、Jinja2、Bootstrap、零基础入门、CSDN 教程
🌟 前言
还记得我们之前用 Java 写的“电视剧趣推系统”吗?👉 回顾文章
今天,我们要把它升级为 Web 版!使用 Python + Flask + HTML 模板,打造一个可以在浏览器中访问的推荐系统!
🎯 本项目目标:
- ✅ 将 Java 控制台程序转为 Web 应用
- ✅ 使用 Flask 构建后端 API 与页面路由
- ✅ 用 Jinja2 模板渲染前端页面
- ✅ 实现用户喜欢、智能推荐、数据管理功能
- ✅ 零数据库依赖,纯内存存储(后续可扩展为 SQLite)
📌 适合人群:Python 入门者、想学 Web 开发的新手、对推荐系统感兴趣的同学。
🧱 一、项目功能概览
功能 | 说明 |
---|---|
📺 浏览所有剧集 | 在网页上查看电视剧列表 |
❤️ 点击“喜欢”按钮 | 用户可标记喜欢的剧 |
🔮 智能推荐 | 根据用户偏好推荐同类高分剧 |
👤 用户切换 | 支持多个用户,记住各自喜好 |
🖥️ Web 界面 | Bootstrap 美化,响应式布局 |
✅ 技术栈:
Flask
:轻量级 Web 框架Jinja2
:HTML 模板引擎Bootstrap
:前端样式库session
:用户状态管理
🗂️ 二、项目目录结构
tv_recommender/
├── app.py → Flask 主程序
├── templates/ → HTML 页面模板
│ ├── base.html → 布局母版
│ ├── index.html → 首页(浏览+喜欢)
│ ├── recommend.html → 推荐页
│ └── users.html → 用户管理页
├── static/
│ └── style.css → 自定义样式(可选)
└── data.py → 模拟数据初始化(可选分离)
💡 提示:Flask 默认会从
templates/
找 HTML,从static/
找 CSS/JS。
💻 三、环境准备
1. 安装 Python(建议 3.7+)
python --version
2. 安装 Flask
pip install flask
✅ 验证安装:
python -c "from flask import Flask; print('Flask installed!')"
🧩 四、核心数据模型设计(Python 类)
我们先定义两个类:TVShow
和 User
,对应 Java 中的实体。
✅ TVShow
类 —— 电视剧
# tv_show.py (或直接写在 app.py 中)
class TVShow:
def __init__(self, show_id, title, genre, rating, description):
self.id = show_id
self.title = title
self.genre = genre
self.rating = rating
self.description = description
def __repr__(self):
return f"<TVShow {self.title}>"
def to_dict(self):
"""方便传递给前端"""
return {
'id': self.id,
'title': self.title,
'genre': self.genre,
'rating': self.rating,
'description': self.description
}
✅ User
类 —— 用户
class User:
def __init__(self, user_id, name):
self.id = user_id
self.name = name
self.liked_show_ids = set() # 用 set 防止重复
def like(self, show_id):
self.liked_show_ids.add(show_id)
def has_liked(self, show_id):
return show_id in self.liked_show_ids
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'liked_count': len(self.liked_show_ids)
}
⚙️ 五、推荐引擎逻辑(核心算法)
def get_recommendations(user, all_shows, all_users):
"""
为用户生成推荐列表
"""
if user is None or not user.liked_show_ids:
# 用户未登录或未喜欢任何剧 → 推荐全局高分TOP5
return sorted(all_shows.values(), key=lambda x: x.rating, reverse=True)[:5]
# 统计用户最喜欢哪种类型
genre_count = {}
for show_id in user.liked_show_ids:
show = all_shows.get(show_id)
if show:
genre = show.genre
genre_count[genre] = genre_count.get(genre, 0) + 1
# 找出最喜欢的类型
favorite_genre = max(genre_count, key=genre_count.get) if genre_count else "Drama"
# 推荐该类型中评分高且未被喜欢的剧
recommendations = []
for show in all_shows.values():
if show.genre == favorite_genre and show.id not in user.liked_show_ids:
recommendations.append(show)
# 按评分排序,取前5部
recommendations.sort(key=lambda x: x.rating, reverse=True)
return recommendations[:5]
🧠 逻辑解析:
- 若无偏好 → 推高分剧
- 有偏好 → 统计类型频次 → 推同类未看高分剧
🖥️ 六、Flask 主程序 —— app.py
from flask import Flask, render_template, request, redirect, url_for, session
import os
# 初始化 Flask 应用
app = Flask(__name__)
app.secret_key = 'your-secret-key-here' # 用于 session 加密
# ==================== 数据初始化 ====================
# 所有电视剧
shows = {
"s001": TVShow("s001", "Breaking Bad", "Crime", 9.5, "化学老师变毒枭"),
"s002": TVShow("s002", "Stranger Things", "Sci-Fi", 8.7, "80年代超自然谜团"),
"s003": TVShow("s003", "The Office", "Comedy", 9.0, "办公室搞笑日常"),
"s004": TVShow("s004", "Game of Thrones", "Fantasy", 9.2, "权力的游戏"),
"s005": TVShow("s005", "Dark", "Sci-Fi", 8.8, "时间旅行之谜"),
}
# 所有用户
users = {
"u001": User("u001", "Alice"),
"u002": User("u002", "Bob"),
}
# 当前登录用户 ID(模拟)
CURRENT_USER_ID = "u001" # 可扩展为多用户登录
# ==================== 路由定义 ====================
@app.route('/')
def index():
current_user = users.get(CURRENT_USER_ID)
all_shows = list(shows.values())
return render_template('index.html',
shows=all_shows,
user=current_user,
shows=shows.values(),
user=current_user)
@app.route('/like/<show_id>')
def like_show(show_id):
user = users.get(CURRENT_USER_ID)
if user and show_id in shows:
user.like(show_id)
return redirect(url_for('index'))
@app.route('/recommend')
def recommend():
user = users.get(CURRENT_USER_ID)
recs = get_recommendations(user, shows, users)
return render_template('recommend.html',
recommendations=recs,
user=user)
@app.route('/users')
def list_users():
return render_template('users.html', users=users.values())
# ==================== 启动入口 ====================
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
✅
debug=True
开启调试模式,代码修改自动重启。
🎨 七、前端页面设计(HTML + Bootstrap)
1. 布局母版 —— templates/base.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电视剧趣推系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.card { margin-bottom: 1rem; }
.btn-like { background-color: #e74c3c; color: white; }
.btn-like:hover { background-color: #c0392b; }
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">📺 趣推系统</a>
<div class="navbar-nav">
<a class="nav-link" href="/">首页</a>
<a class="nav-link" href="/recommend">推荐</a>
<a class="nav-link" href="/users">用户</a>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
2. 首页 —— templates/index.html
{% extends "base.html" %}
{% block content %}
<h2>🎬 所有电视剧</h2>
<p class="text-muted">当前用户:{{ user.name }}</p>
<div class="row">
{% for show in shows %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">{{ show.title }}</h5>
<p class="card-text text-muted">
{{ show.genre }} | ⭐ {{ show.rating }}
</p>
<p class="card-text">{{ show.description }}</p>
{% if user.has_liked(show.id) %}
<span class="badge bg-success">已喜欢</span>
{% else %}
<a href="/like/{{ show.id }}" class="btn btn-sm btn-like">❤️ 喜欢</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
3. 推荐页 —— templates/recommend.html
{% extends "base.html" %}
{% block content %}
<h2>✨ 为你推荐</h2>
<p class="text-muted">基于你的喜好:科幻、高分优先</p>
{% if recommendations %}
<div class="row">
{% for show in recommendations %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ show.title }}</h5>
<p class="card-text text-muted">{{ show.genre }} | ⭐ {{ show.rating }}</p>
<p class="card-text">{{ show.description }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">暂无推荐内容,请先喜欢一些剧集!</div>
{% endif %}
<a href="/" class="btn btn-primary">返回首页</a>
{% endblock %}
4. 用户页 —— templates/users.html
{% extends "base.html" %}
{% block content %}
<h2>👥 用户列表</h2>
<table class="table table-striped">
<thead>
<tr>
<th>用户名</th>
<th>喜欢数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for u in users %}
<tr>
<td>{{ u.name }}</td>
<td>{{ u.liked_count }}</td>
<td>
<a href="/recommend" class="btn btn-sm btn-outline-primary">查看推荐</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="/" class="btn btn-secondary">返回首页</a>
{% endblock %}
▶️ 八、运行教程(手把手教学)
步骤 1:创建文件夹和文件
tv_recommender/
├── app.py
├── templates/
│ ├── base.html
│ ├── index.html
│ ├── recommend.html
│ └── users.html
步骤 2:安装 Flask(如未安装)
pip install flask
步骤 3:运行程序
cd tv_recommender
python app.py
✅ 输出:
* Running on http://127.0.0.1:5000
步骤 4:打开浏览器访问
👉 访问:http://127.0.0.1:5000
🖼️ 九、运行效果模拟(文字版)
首页 /
- 显示 5 部电视剧卡片
- Alice 用户看到《Stranger Things》旁有 ❤️ 按钮
- 点击后变为“已喜欢”
推荐页 /recommend
- 显示《Dark》等科幻高分剧
- 因为 Alice 喜欢过《Stranger Things》(Sci-Fi)
用户页 /users
- 列出 Alice 和 Bob
- 显示每人喜欢数量
🔍 十、常见问题与解决方案
问题 | 解决方案 |
---|---|
TemplateNotFound | 检查 templates/ 文件夹名是否拼写正确 |
jinja2.exceptions.UndefinedError | 检查变量名是否传入 render_template() |
Method Not Allowed | 确保 POST 请求有 @app.route(..., methods=['POST']) |
PickleError with session | 不要存复杂对象到 session ,只存 ID |
🔮 十一、扩展方向(进阶练习)
方向 | 实现思路 |
---|---|
🗄️ SQLite 数据库 | 用 sqlite3 存储 shows 和 users |
🔐 用户登录 | 添加登录表单,用 session['user_id'] 记录 |
📊 多标签推荐 | genre 改为 list ,支持“科幻+悬疑” |
📱 REST API | 提供 /api/recommend?user=u001 接口 |
🎨 前端美化 | 引入 Vue/React,做 SPA 单页应用 |
📦 十二、项目打包与部署建议
# 打包为 zip
zip -r tv_recommender.zip tv_recommender/
# 部署到云服务器(Ubuntu)
sudo apt install python3-pip
pip3 install flask
nohup python3 app.py &
或使用 gunicorn + nginx
生产部署。
📝 十三、总结
通过本次重构,你学会了:
- ✅ 如何将控制台程序升级为 Web 应用
- ✅ Flask 路由、模板、静态文件管理
- ✅ Jinja2 模板语法(循环、条件、继承)
- ✅ 推荐系统 Web 化实现
- ✅ Python Web 开发全流程
💬 一句话总结:Java 是基础,Python + Flask 是快速落地 Web 项目的利器。掌握它,你就能把想法变成可交互的产品!
❤️ 结束语
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!也欢迎在评论区留下你的运行截图或提问。
📌 关注我,后续将带来:《Flask + SQLite 版》《Vue + Flask 前后端分离》《推荐算法升级:协同过滤》等系列教程!