19.Python实战:实现对博客文章的点赞系统
Flask博客点赞系统
一个基于Flask的简单博客系统,具有文章展示和点赞功能。系统使用MySQL存储数据,支持文章展示、点赞/取消点赞等功能。
功能特点
- 文章列表展示
- 文章详情查看(模态框展示)
- 点赞/取消点赞功能(每个IP只能点赞一次)
- 响应式设计,支持移动端
- 优雅的动画效果
- 实时点赞数更新
技术栈
- 后端:Flask
- 数据库:MySQL
- 前端:
- Bootstrap 5
- jQuery
- Font Awesome 5 (心形图标)
系统要求
- Python 3.6+
- MySQL 5.7+
项目结构
├── README.md
├── requirements.txt
├── schema.sql
├── app.py
├── insert_test_data.py
└── templates/└── index.html
安装步骤
- 克隆项目到本地
- 安装依赖包
pip install -r requirements.txt
- 创建数据库和表
CREATE DATABASE blog_db;
USE blog_db;
运行schema.sql中的建表语句
source schema.sql;
- 修改数据库配置
在app.py
中修改数据库连接信息:
db_config = {'host': 'your_host','port': your_port,'user': 'your_username','password': 'your_password','database': 'blog_db'
}
- 插入测试数据
python insert_test_data.py
- 运行应用
python app.py
访问 http://localhost:5000 即可看到效果
文件说明
app.py
: 主应用文件,包含所有路由和业务逻辑schema.sql
: 数据库表结构requirements.txt
: 项目依赖insert_test_data.py
: 测试数据生成脚本templates/index.html
: 前端模板文件
数据库设计
articles表
- id: 文章ID
- title: 文章标题
- content: 文章内容
- author: 作者
- publish_time: 发布时间
- likes: 点赞数
user_likes表
- id: 记录ID
- article_id: 文章ID(外键)
- user_ip: 用户IP
- created_at: 点赞时间
API接口
获取文章列表
- 路由:
GET /
- 返回:渲染后的文章列表页面
获取文章内容
- 路由:
GET /article/<article_id>
- 返回:文章内容的JSON数据
点赞/取消点赞
- 路由:
POST /like/<article_id>
- 返回:更新后的点赞数和操作状态的JSON数据
注意事项
- 确保MySQL服务已启动
- 检查数据库连接配置是否正确
- 确保所需端口未被占用
- 建议在虚拟环境中运行项目
可能的改进方向
- 添加用户认证系统
- 实现文章评论功能
- 添加文章分类和标签
- 实现文章搜索功能
- 添加管理后台
- 优化移动端体验
- 添加文章分享功能
1.requirements.txt
flask==2.0.1
mysql-connector-python==8.0.26
2.schema.sql
CREATE DATABASE blog_db;
USE blog_db;
CREATE TABLE IF NOT EXISTS articles (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(200) NOT NULL,content TEXT NOT NULL,author VARCHAR(100) NOT NULL,publish_time DATETIME NOT NULL,likes INT DEFAULT 0
);CREATE TABLE IF NOT EXISTS user_likes (id INT AUTO_INCREMENT PRIMARY KEY,article_id INT NOT NULL,user_ip VARCHAR(50) NOT NULL,created_at DATETIME NOT NULL,UNIQUE KEY unique_like (article_id, user_ip),FOREIGN KEY (article_id) REFERENCES articles(id)
);
3.dianzan.py
from flask import Flask, render_template, jsonify, request
import mysql.connector
from datetime import datetimeapp = Flask(__name__)数据库配置
db_config = {'host': 'localhost','port': 'port','user': 'your_username','password': 'your_password','database': 'blog_db'
}def get_db():return mysql.connector.connect(**db_config)@app.route('/')
def index():conn = get_db()cursor = conn.cursor(dictionary=True)# 获取用户IPuser_ip = request.remote_addr# 获取文章列表和用户点赞状态cursor.execute("""SELECT a.*, CASE WHEN ul.id IS NOT NULL THEN 1 ELSE 0 END as user_likedFROM articles aLEFT JOIN user_likes ul ON a.id = ul.article_id AND ul.user_ip = %sORDER BY a.publish_time DESC""", (user_ip,))articles = cursor.fetchall()cursor.close()conn.close()return render_template('index.html', articles=articles)@app.route('/article/<int:article_id>')
def get_article(article_id):conn = get_db()cursor = conn.cursor(dictionary=True)cursor.execute("SELECT content FROM articles WHERE id = %s", (article_id,))article = cursor.fetchone()cursor.close()conn.close()if article is None:return jsonify({'error': 'Article not found'}), 404return jsonify({'content': article['content']})@app.route('/like/<int:article_id>', methods=['POST'])
def like_article(article_id):conn = get_db()cursor = conn.cursor()user_ip = request.remote_addrtry:# 检查是否已经点赞cursor.execute("""SELECT id FROM user_likes WHERE article_id = %s AND user_ip = %s""", (article_id, user_ip))existing_like = cursor.fetchone()if existing_like:# 如果已经点赞,则取消点赞cursor.execute("""DELETE FROM user_likes WHERE article_id = %s AND user_ip = %s""", (article_id, user_ip))cursor.execute("""UPDATE articles SET likes = likes - 1 WHERE id = %s""", (article_id,))action = 'unliked'else:# 如果未点赞,则添加点赞cursor.execute("""INSERT INTO user_likes (article_id, user_ip, created_at) VALUES (%s, %s, %s)""", (article_id, user_ip, datetime.now()))cursor.execute("""UPDATE articles SET likes = likes + 1 WHERE id = %s""", (article_id,))action = 'liked'conn.commit()# 获取最新点赞数cursor.execute("SELECT likes FROM articles WHERE id = %s", (article_id,))likes = cursor.fetchone()[0]cursor.close()conn.close()return jsonify({'likes': likes, 'action': action})except mysql.connector.Error as err:conn.rollback()cursor.close()conn.close()return jsonify({'error': str(err)}), 500# 添加一个用于插入测试数据的辅助函数
def add_test_article(title, content, author):conn = get_db()cursor = conn.cursor()cursor.execute("INSERT INTO articles (title, content, author, publish_time, likes) VALUES (%s, %s, %s, %s, %s)",(title, content, author, datetime.now(), 0))conn.commit()cursor.close()conn.close()if __name__ == '__main__':app.run(debug=True)
4.insert_test_data.py
from app import get_db
from datetime import datetime, timedeltadef insert_test_data():conn = get_db()cursor = conn.cursor()# 准备测试数据test_articles = [{'title': '人工智能发展现状与未来趋势','content': '''人工智能技术正在快速发展,从机器学习到深度学习,从计算机视觉到自然语言处理,各个领域都取得了突破性进展。本文将详细介绍AI领域的最新发展动态和未来发展方向。近年来的主要突破:1. 大规模语言模型的突破2. 自动驾驶技术的进展3. AI在医疗领域的应用未来展望:- 更强大的多模态AI系统- 更高效的算法和架构- 更广泛的商业应用场景''','author': '张智能','likes': 42},{'title': '5G技术应用与产业变革','content': '''5G作为新一代移动通信技术,正在深刻改变着各个行业。本文将分析5G技术在工业互联网、智慧城市等领域的具体应用案例。主要应用领域:1. 工业自动化2. 远程医疗3. 车联网4. 智慧城市建设产业影响:- 制造业智能化转型- 服务业数字化升级- 新业态快速涌现''','author': '李网络','likes': 38},{'title': '区块链技术与金融创新','content': '''区块链技术正在重塑金融服务业,从支付结算到供应链金融,带来了全新的业务模式和机遇。本文深入分析区块链在金融领域的创新应用。技术优势:1. 去中心化2. 不可篡改3. 智能合约应用场景:- 跨境支付- 供应链金融- 数字货币- 资产数字化''','author': '王区块','likes': 25}]# 插入测试数据for article in test_articles:# 随机生成过去7天内的时间random_days = timedelta(days=random.randint(0, 7),hours=random.randint(0, 23),minutes=random.randint(0, 59))publish_time = datetime.now() - random_dayscursor.execute("INSERT INTO articles (title, content, author, publish_time, likes) ""VALUES (%s, %s, %s, %s, %s)",(article['title'], article['content'], article['author'],publish_time, article['likes']))conn.commit()cursor.close()conn.close()print("测试数据插入成功!")if __name__ == '__main__':import randominsert_test_data()
5.templates/index.html
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>博客点赞系统</title><link href="https://cdn.bootcdn.net/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"><style>.article-card {transition: transform 0.2s;cursor: pointer;}.article-card:hover {transform: translateY(-5px);box-shadow: 0 4px 15px rgba(0,0,0,0.1);}.like-btn {transition: all 0.2s;padding: 8px 12px;border-radius: 50%;width: 45px;height: 45px;display: flex;align-items: center;justify-content: center;}.like-btn:hover {transform: scale(1.1);}.like-btn .fa-heart {font-size: 1.2em;}.like-btn.liked {background-color: #ff4757;border-color: #ff4757;color: white;}.like-btn.liked:hover {background-color: #ff6b81;border-color: #ff6b81;}.like-count {font-size: 0.9em;color: #666;margin-top: 5px;}</style>
</head>
<body><div class="container py-5"><h1 class="text-center mb-5">博客文章</h1><div class="row">{% for article in articles %}<div class="col-md-6 mb-4"><div class="card article-card"><div class="card-body"><h5 class="card-title article-title" data-id="{{ article.id }}">{{ article.title }}</h5><div class="d-flex justify-content-between align-items-center"><div class="text-muted"><small>作者: {{ article.author }}</small><br><small>发布时间: {{ article.publish_time.strftime('%Y-%m-%d %H:%M') }}</small></div><div class="text-center"><button class="btn btn-outline-primary like-btn {% if article.user_liked %}liked{% endif %}"data-id="{{ article.id }}"><i class="{% if article.user_liked %}fas{% else %}far{% endif %} fa-heart"></i></button><div class="like-count mt-1" id="likes-{{ article.id }}">{{ article.likes }} 赞</div></div></div></div></div></div>{% endfor %}</div></div><!-- 文章内容模态框 --><div class="modal fade" id="articleModal" tabindex="-1"><div class="modal-dialog modal-lg"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">文章内容</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div id="articleContent"></div></div></div></div></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script><script>$(document).ready(function() {// 点赞功能$('.like-btn').click(function(e) {e.stopPropagation();const btn = $(this);const articleId = btn.data('id');const heartIcon = btn.find('i');$.post(`/like/${articleId}`, function(data) {$(`#likes-${articleId}`).text(data.likes + ' 赞');if (data.action === 'liked') {btn.addClass('liked');heartIcon.removeClass('far').addClass('fas');} else {btn.removeClass('liked');heartIcon.removeClass('fas').addClass('far');}});});// 查看文章内容$('.article-title').click(function() {const articleId = $(this).data('id');$.get(`/article/${articleId}`, function(data) {$('#articleContent').html(data.content);$('#articleModal').modal('show');});});});</script>
</body>
</html>
相关文章:
19.Python实战:实现对博客文章的点赞系统
Flask博客点赞系统 一个基于Flask的简单博客系统,具有文章展示和点赞功能。系统使用MySQL存储数据,支持文章展示、点赞/取消点赞等功能。 功能特点 文章列表展示文章详情查看(模态框展示)点赞/取消点赞功能(每个IP只…...
【stm32】定时器输出PWM波形(hal库)
一. PWM基本原理 PWM是一种通过调节信号的占空比(Duty Cycle)来控制输出平均电压的技术。占空比是指高电平时间与整个周期时间的比值。例如: - 占空比为50%时,输出平均电压为电源电压的一半。 - 占空比为100%时,输出始…...

当Ollama遇上划词翻译:我的Windows本地AI服务搭建日记
🚀 实现Windows本地大模型翻译服务 - 基于OllamaFlask的划词翻译实践 🛠️ 步骤概要1️⃣ python 环境准备2️⃣ Ollama 安装3️⃣ 一个 Flask 服务4️⃣ Windows 服务化封装5️⃣ 测试本地接口6️⃣ 配置划词翻译自定义翻译源7️⃣ 效果展示8️⃣ debug…...
Linux上Elasticsearch 集群部署指南
Es 集群部署 Es 集群部署 Es 集群部署 准备好三台服务器。示例使用:110.0.5.141/142/143 1、es用户和用户组创建,使用root账号 groupadd esuseradd -g es es2、将es安装包和ik分词器上传到:/home/es/目录下(任意目录都行&#…...

字节Trae使用感想(后端)
前言 昨天分享了字节哥的Trae从0到1创作模式构建一个vue前端项目,今天又来试试她的后端项目能力。不是我舔,不得不说确实不错。可惜现在曾经没有好好学习,进不了字节。既然进不了字节,那我就用字节哥的产品吧。 后面有惊喜…...

国产编辑器EverEdit - 二进制模式下观察Window/Linux/MacOs换行符差异
1 换行符格式 1.1 应用场景 稍微了解计算机历史的人都知道, 计算机3大操作系统: Windows、Linux/Unix、MacOS,这3大系统对文本换行的定义各不相同,且互不相让,导致在文件的兼容性方面存在一些问题,比如它们…...

文心一言4月起全面免费,6月底开源新模型:AI竞争进入新阶段?
名人说:莫听穿林打叶声,何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、文心一言免费化的背后:AI成本与应用的双重驱动1️⃣成本下降,推动文心一言普及2…...

解锁机器学习算法 | 线性回归:机器学习的基石
在机器学习的众多算法中,线性回归宛如一块基石,看似质朴无华,却稳稳支撑起诸多复杂模型的架构。它是我们初涉机器学习领域时便会邂逅的算法之一,其原理与应用广泛渗透于各个领域。无论是预测房价走势、剖析股票市场波动࿰…...
如何使用Three.js制作3D月球与星空效果
目录 1. 基本设置2. 创建星空效果3. 创建月球模型4. 添加中文3D文字5. 光照与相机配置6. 动画与控制7. 响应式布局8. 结语 在本文中,我们将一起学习如何利用Three.js实现一个3D月球与星空的效果,并添加一些有趣的元素,比如中文3D文字和互动功…...
SQL语句语法
SQL数据库的结构为 库database 表table 段segment 行row 列column 或field SQL 语句主要分为以下几类: 数据定义语言(DDL):用于定义数据库对象,如数据库、表、视图、索引等。数据操作语言(DML)&…...
github上文件过大无法推送问题
GitHub 对文件大小有限制,超过 100 MB 的文件无法直接推送到仓库中。 解决思路: 使用 Git Large File Storage (Git LFS) 来管理大文件不上传对应的大文件 使用Git LFS: 1. 安装 Git LFS 首先,你需要安装 Git LFS。可以按照以…...
微信小程序的请求函数封装(ts版本,uniapp开发)
主要封装函数代码: interface HttpOptions {url: string;method?: string;headers?: { [key: string]: string };data?: any; }class Http {private timeout: number;private baseUrl: string;public constructor() { this.timeout 60 * 1000;this.baseUrl ht…...

Visual Studio Code支持WSL,直接修改linux/ubuntu中的文件
步骤1 开始通过 WSL 使用 VS Code | Microsoft Learn 点击远程开发扩展包。 步骤2 Remote Development - Visual Studio Marketplace 点击install, 允许打开Visual Studio Code。 步骤3 共有4项,一齐安装。 步骤4 在WSL Linux(Ubuntu)中…...

openAI最新o1模型 推理能力上表现出色 准确性方面提升 API如何接入?
OpenAI o1模型在回答问题前会进行深入思考,并生成一条内部推理链,使其在尝试解决问题时可以识别并纠正错误,将复杂的步骤分解为更简单的部分,并在当前方法无效时尝试不同的途径。据悉,o1不仅数学水平与美国奥林匹克竞赛…...

GC 基础入门
什么是GC(Garbage Collection)? 内存管理方式通常分为两种: 手动内存管理(Manual Memory Management)自动内存管理(Garbage Collection, GC) 手动内存管理 手动内存管理是指开发…...
Go语言协程Goroutine高级用法(一)
什么协程 在Go语言中,协程就是一种轻量的线程,是并发编程的单元,由Go来管理,所以在GO层面的协程会更加的轻量、高效、开销更小,并且更容易实现并发编程。 轻量级线程 Go语言中协程(线程)与传…...

DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件
1 DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件 1.1 背景 AI能力再强,如果不能在企业的自有业务上产生助益,那基本也是一无是处。将企业的自有业务上传到线上训练,那是脑子进水的做法ÿ…...

【鸿蒙HarmonyOS Next实战开发】lottie动画库
简介 lottie是一个适用于OpenHarmony和HarmonyOS的动画库,它可以解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画,并在移动设备上进行本地渲染。 下载安裝 ohpm install ohos/lottieOpenHarmony ohpm 环境配置等更多内容,…...

PAT乙级真题 — 1084 外观数列(java)
外观数列是指具有以下特点的整数序列: d, d1, d111, d113, d11231, d112213111, ...它从不等于 1 的数字 d 开始,序列的第 n1 项是对第 n 项的描述。比如第 2 项表示第 1 项有 1 个 d,所以就是 d1;第 2 项是 1 个 d(对…...

从 ClickHouse 到 Apache Doris:在网易云音乐日增万亿日志数据场景下的落地
导读:日志数据已成为企业洞察系统状态、监控网络安全及分析业务动态的宝贵资源。网易云音乐引入 Apache Doris 作为日志库新方案,替换了 ClickHouse。解决了 ClickHouse 运维复杂、不支持倒排索引的问题。目前已经稳定运行 3 个季度,规模达到…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...