Python 30 天进阶:继续完善个人博客网站

在前一篇搭建起个人博客网站的基础框架后,今天我们要进一步完善它,从优化前端页面设计入手,融入 JavaScript 来增添交互功能,同时完善博客文章的分类和标签相关功能,让这个博客网站更加实用且用户体验更佳。

一、前端页面优化与 JavaScript 交互功能实现

(一)页面样式优化


可以使用更丰富的 CSS 属性和框架(如 Bootstrap 等,这里以原生 CSS 继续拓展为例)来进一步美化页面。例如,调整文章列表的排版,让文章标题和简介展示得更清晰美观:

article {
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 15px;
    margin-bottom: 20px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

article h2 {
    margin-top: 0;
}

article p {
    margin-bottom: 0;
}



通过上述 CSS 代码,为每篇文章添加了边框、圆角、阴影等样式,让文章展示更具层次感和立体感,同时对文章内的标题和段落元素做了一些间距调整。

(二)文章点赞功能(结合 JavaScript 与后端交互)



  1. 后端 API 设计(Flask 路由)
    首先在后端创建用于处理点赞操作的路由,示例代码如下:
@app.route('/article/like/<int:article_id>', methods=['POST'])
def like_article(article_id):
    article = db_session.query(Article).filter_by(id=article_id).first()
    if article:
        # 这里简单模拟点赞数加 1,实际可根据需求完善逻辑,比如记录点赞用户等
        article.likes += 1
        db_session.commit()
        return jsonify({'success': True, 'likes': article.likes})
    return jsonify({'success': False})



在上述代码中,定义了一个接收文章 id 的 POST 路由,用于处理点赞请求。当接收到请求后,从数据库中查找对应的文章,如果找到则增加文章的点赞数(假设 Article 类中新增了 likes 属性用于记录点赞数),提交事务后返回包含操作成功状态以及当前点赞数的 JSON 数据,若文章不存在则返回操作失败的 JSON 数据。



  1. 前端 JavaScript 实现
    在文章详情页面(article_detail.html)中引入 JavaScript 代码来发送点赞请求,示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>个人博客 - 文章详情</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
    <script>
        function likeArticle(articleId) {
            fetch(`/article/like/${articleId}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                }
            })
           .then(response => response.json())
           .then(data => {
                if (data.success) {
                    document.getElementById('like-count').innerText = `点赞数: ${data.likes}`;
                } else {
                    alert('点赞失败,请稍后再试');
                }
            });
        }
    </script>
</head>
<body>
    <h1>{{ article.title }}</h1>
    <div class="article-content">
        {{ article.content }}
    </div>
    <button onclick="likeArticle({{ article.id }})">点赞</button>
    <span id="like-count">点赞数: {{ article.likes }}</span>
</body>
</html>



在上述 HTML 页面中,添加了一个 script 标签,里面定义了 likeArticle 函数,该函数使用 fetch API 发送 POST 请求到后端的点赞路由,传递文章 id 参数。根据后端返回的 JSON 数据,若点赞成功则更新页面上显示的点赞数,若失败则弹出提示框告知用户。同时,在页面中添加了点赞按钮,并绑定 likeArticle 函数,传递当前文章的 id 值,还显示了初始的点赞数。

(三)评论功能(前后端交互实现)



  1. 数据库表结构设计(新增评论表)
class Comment(Base):
    __tablename__ = 'comments'
    id = Column(Integer, primary_key=True)
    article_id = Column(Integer, ForeignKey('articles.id'))
    commenter_name = Column(String(50), nullable=False)
    comment_content = Column(Text, nullable=False)
    comment_time = Column(DateTime, default=func.now())

Base.metadata.create_all(engine)



上述代码定义了 Comment 类对应数据库中的 comments 表,包含评论的唯一标识 id、关联的文章 id(通过外键与 articles 表关联)、评论者姓名、评论内容以及评论时间等字段,这样就能记录每篇文章的相关评论信息了。



  1. 后端路由与评论处理逻辑
@app.route('/article/comment/<int:article_id>', methods=['POST'])
def add_comment(article_id):
    data = request.get_json()
    commenter_name = data.get('commenter_name')
    comment_content = data.get('comment_content')
    new_comment = Comment(article_id=article_id, commenter_name=commenter_name, comment_content=comment_content)
    db_session.add(new_comment)
    db_session.commit()
    return jsonify({'success': True})



这里定义了处理文章评论添加的路由,接收文章 id 以及从前端发送过来的 JSON 格式的评论者姓名和评论内容数据,创建 Comment 对象并添加到数据库,提交事务后返回操作成功的 JSON 数据。



  1. 前端 JavaScript 实现评论提交与展示(简单示例)
    在文章详情页面添加以下 JavaScript 代码用于评论相关功能:
<script>
    function addComment(articleId) {
        const commenterName = document.getElementById('commenter-name').value;
        const commentContent = document.getElementById('comment-content').value;
        fetch(`/article/comment/${articleId}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                commenter_name: commenterName,
                comment_content: commentContent
            })
        })
       .then(response => response.json())
       .then(data => {
            if (data.success) {
                // 这里简单模拟添加评论后刷新页面来展示新评论,实际可优化为局部更新
                location.reload();
            } else {
                alert('评论发布失败,请稍后再试');
            }
        });
    }
</script>
...
<div>
    <input type="text" id="commenter-name" placeholder="请输入您的姓名">
    <textarea id="comment-content" placeholder="请输入您的评论"></textarea>
    <button onclick="addComment({{ article.id }})">发布评论</button>
</div>



在上述代码中,定义了 addComment 函数,用于获取用户在输入框中输入的评论者姓名和评论内容,然后通过 fetch 发送 POST 请求到后端评论添加路由,传递相应数据。根据后端返回的结果,若成功则刷新页面展示新评论(可优化为只局部更新评论区域),若失败则弹出提示框告知用户。同时在页面中添加了输入框和按钮等元素用于用户输入和提交评论。

(四)页面动态加载效果(使用 JavaScript)



例如,在文章列表页面实现当滚动到底部时动态加载更多文章的效果,示例 JavaScript 代码如下(需要结合后端分页查询文章的功能,这里先简单展示前端思路):

<script>
    window.addEventListener('scroll', function () {
        if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
            // 这里发送请求获取下一页文章数据,可通过调用后端分页查询的 API
            // 假设后端有 /articles?page=2 这样的路由用于获取第二页文章
            fetch('/articles?page=2')
           .then(response => response.json())
           .then(data => {
                const articleList = document.getElementById('article-list');
                data.articles.forEach(article => {
                    const articleElement = document.createElement('article');
                    articleElement.innerHTML = `<h2>${article.title}</h2><p>${article.content}</p>`;
                    articleList.appendChild(articleElement);
                });
            });
        }
    });
</script>
...
<body>
    <h1>我的博客文章列表</h1>
    <ul id="article-list">
        {% for article in articles %}
        <li><a href="{{ url_for('article_detail', article_id=article.id) }}">{{ article.title }}</a></li>
        {% endfor %}
    </ul>
</body>



在上述代码中,通过监听页面的 scroll 事件,当滚动到页面底部(通过判断滚动高度和窗口高度与页面总高度的关系)时,发送请求到后端获取下一页文章数据(这里假设后端有相应的分页查询路由),然后将获取到的文章数据动态创建 HTML 元素并添加到文章列表中,实现动态加载更多文章的效果。

二、博客文章的分类和标签功能完善

(一)数据库表结构设计



  1. 分类表(Category)
class Category(Base):
    __tablename__ = 'categories'
    id = Column(Integer, primary_key=True)
    category_name = Column(String(50), nullable=False)

Base.metadata.create_all(engine)



定义了 Category 表用于存储文章的分类信息,包含分类的唯一标识 id 和分类名称 category_name 字段。



  1. 标签表(Tag)
class Tag(Base):
    __tablename__ = 'tags'
    id = Column(Integer, primary_key=True)
    tag_name = Column(String(50), nullable=False)

Base.metadata.create_all(engine)



Tag 表用于存储文章的标签信息,同样包含 id 和 tag_name 字段。



  1. 文章与分类、标签关联表(ArticleCategory、ArticleTag)
class ArticleCategory(Base):
    __tablename__ = 'article_categories'
    article_id = Column(Integer, ForeignKey('articles.id'), primary_key=True)
    category_id = Column(Integer, ForeignKey('categories.id'), primary_key=True)

class ArticleTag(Base):
    __tablename__ = 'article_tags'
    article_id = Column(Integer, ForeignKey('articles.id'), primary_key=True)
    tag_id = Column(Integer, ForeignKey('tags.id'), primary_key=True)

Base.metadata.create_all(engine)



通过这两个关联表,建立了文章与分类、文章与标签之间多对多的关系,方便后续进行分类筛选和标签筛选展示文章的操作。

(二)后端路由与数据查询逻辑(以分类筛选为例)

@app.route('/category/<int:category_id>')
def articles_by_category(category_id):
    articles = db_session.query(Article).join(ArticleCategory).filter(ArticleCategory.category_id == category_id).all()
    return render_template('article_list.html', articles=articles)



上述代码定义了根据分类 id 筛选文章的路由,通过数据库的 join 操作,基于 ArticleCategory 关联表,筛选出属于指定分类的文章,然后将这些文章传递给文章列表模板进行展示,实现分类筛选文章的功能。

(三)前端页面实现分类和标签筛选展示(简单示例)



在文章列表页面添加分类和标签筛选的 HTML 元素及 JavaScript 交互代码,示例如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>个人博客 - 文章列表</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
    <script>
        function filterByCategory(categoryId) {
            window.location.href = `/category/${categoryId}`;
        }

        function filterByTag(tagId) {
            // 类似分类筛选,需后端实现根据标签筛选文章的路由,这里暂省略
            window.location.href = `/tag/${tagId}`;
        }
    </script>
</head>

<body>
    <h1>我的博客文章列表</h1>
    <div>
        <h3>分类筛选:</h3>
        {% for category in categories %}
        <button onclick="filterByCategory({{ category.id }})">{{ category.category_name }}</button>
        {% endfor %}
    </div>
    <div>
        <h3>标签筛选:</h3>
        {% for tag in tags %}
        <button onclick="filterByTag({{ tag.id }})">{{ tag.tag_name }}</button>
        {% endfor %}
    </div>
    <ul>
        {% for article in articles %}
        <li><a href="{{ url_for('article_detail', article_id=article.id) }}">{{ article.title }}</a></li>
        {% endfor %}
    </ul>
</body>

</html>


在上述页面中,通过 Jinja2 模板引擎遍历从后端传递过来的分类和标签列表,为每个分类和标签生成一个按钮,点击按钮时调用相应的 JavaScript 函数,函数内通过修改 window.location.href 将页面跳转到后端对应的分类或标签筛选路由(后端标签筛选路由暂未完整展示,可参照分类筛选路由进行实现),从而实现根据分类和标签筛选展示文章的功能。



通过今天对个人博客网站的进一步完善,我们添加了诸多实用且有趣的交互功能,同时完善了文章分类和标签相关的功能,让博客网站更加符合实际使用场景,用户体验也得到了显著提升。后续还可以继续优化性能、添加更多功能,如用户权限管理、文章搜索功能等。



#个人博客完善# #Web 应用拓展# #前端交互功能# #数据库设计优化# #博客分类标签# #Python Web 编程进阶#