19.Python实战:实现对博客文章的点赞系统

发布于:2025-02-16 ⋅ 阅读:(29) ⋅ 点赞:(0)

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

安装步骤

  1. 克隆项目到本地
  2. 安装依赖包
pip install -r requirements.txt
  1. 创建数据库和表
CREATE DATABASE blog_db;
USE blog_db;

运行schema.sql中的建表语句

source schema.sql;
  1. 修改数据库配置
    app.py中修改数据库连接信息:
db_config = {
    'host': 'your_host',
    'port': your_port,
    'user': 'your_username',
    'password': 'your_password',
    'database': 'blog_db'
}
  1. 插入测试数据
python insert_test_data.py
  1. 运行应用
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数据

注意事项

  1. 确保MySQL服务已启动
  2. 检查数据库连接配置是否正确
  3. 确保所需端口未被占用
  4. 建议在虚拟环境中运行项目

可能的改进方向

  1. 添加用户认证系统
  2. 实现文章评论功能
  3. 添加文章分类和标签
  4. 实现文章搜索功能
  5. 添加管理后台
  6. 优化移动端体验
  7. 添加文章分享功能

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>

网站公告

今日签到

点亮在社区的每一天
去签到