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 datetime
app = 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)
# 获取用户IP
user_ip = request.remote_addr
# 获取文章列表和用户点赞状态
cursor.execute("""
SELECT a.*,
CASE WHEN ul.id IS NOT NULL THEN 1 ELSE 0 END as user_liked
FROM articles a
LEFT JOIN user_likes ul ON a.id = ul.article_id AND ul.user_ip = %s
ORDER 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'}), 404
return 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_addr
try:
# 检查是否已经点赞
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, timedelta
def 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_days
cursor.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 random
insert_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>