当前位置: 首页 > news >正文

博客多级评论展示功能实现

最近在看《Python基础教程(第三版)》。作者提出的编程方法挺适合我的,先写一个能跑的程序,再去谈优化。就算是一坨屎,也得先拉出来。我的感受是,在写的过程中帮助理清了思路,从而才能知道该怎么去优化。

早上突然想起了以前室友面试被问的一个问题“你如何实现一个评论展示的功能”,发现自己并不是很清楚,于是尝试写写。眼过千遍,不如手过一遍。

该功能的实现,我觉得最重要的其实是数据库的设计。

建表语句如下,article_comment中的article_id指向了被评论的文章,parent_id指向了父评论。

CREATE TABLE `article` (`article_id` int NOT NULL AUTO_INCREMENT,`author_id` int NOT NULL,`content` text,`create_time` datetime DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`article_id`)
);CREATE TABLE `article_comment` (`comment_id` int NOT NULL AUTO_INCREMENT,`article_id` int DEFAULT NULL,`user_id` int DEFAULT NULL,`parent_id` int DEFAULT NULL,`level` int DEFAULT NULL,`create_time` datetime DEFAULT CURRENT_TIMESTAMP,`content` text,PRIMARY KEY (`comment_id`)
);

python代码实现如下,主要思路:先根据article_id查出该文章下面的所有评论,然后根据parent_id将评论组装为树形结构。

import json
from contextlib import contextmanager
from dataclasses import dataclassimport uvicorn
from fastapi import FastAPI
from sqlalchemy import create_engine, Column, Integer, String, DateTime, select
from sqlalchemy.orm import DeclarativeBase, sessionmaker, Session, declarative_baseengin = create_engine(url="mysql+pymysql://root:123456@localhost/test",pool_size=10,max_overflow=10,echo = True
)Base = declarative_base()class Article(Base):__tablename__ = 'article'article_id = Column(Integer, primary_key=True)author_id = Column(Integer)content = Column(String)create_time = Column(DateTime)class ArticleComment(Base):__tablename__ = 'article_comment'comment_id = Column(Integer, primary_key=True)article_id = Column(Integer)user_id = Column(Integer)parent_id = Column(Integer)level = Column(Integer)content = Column(String)create_time = Column(DateTime)@contextmanager
def get_db_session():session_maker = sessionmaker(engin)with session_maker() as session:yield sessiondef get_article():with get_db_session() as session:stmt = select(Article).where(Article.article_id == 1)result = session.execute(stmt)# 输出的是对象模式,不是我要的json格式print(result.scalars().first())class CommentNode:def __init__(self, article_comment : ArticleComment):self.comment = article_commentself.children : list[CommentNode] = []def get_comments_tree(id : int):with get_db_session() as session:stmt = select(ArticleComment).where(ArticleComment.article_id == id)all_comment = session.execute(stmt).scalars().all()commentnode_list = [CommentNode(comment) for comment in all_comment]top_comments = []for commentnode in commentnode_list:# 如果评论的parent_id为空,说明该评论是一级评论if not commentnode.comment.parent_id:top_comments.append(commentnode)else:# 找到父节点father_commentnode = find_father_commentnode(commentnode, commentnode_list)# 加入父节点的子节点列表father_commentnode.children.append(commentnode)return top_commentsdef find_father_commentnode(input_commentnode : CommentNode, all_commentnode : list[CommentNode]):for commentnode in all_commentnode:if input_commentnode.comment.parent_id == commentnode.comment.comment_id:return commentnodereturn Noneapp = FastAPI()
@app.get("/")
async def get():return get_comments_tree(1)
uvicorn.run(app)

数据库数据如下所示:

结果如下:

[{"comment": {"parent_id": null,"comment_id": 1,"content": null,"level": null,"article_id": 1,"user_id": 2,"create_time": "2025-07-25T10:18:06"},"children": [{"comment": {"parent_id": 1,"comment_id": 2,"content": null,"level": null,"article_id": 1,"user_id": 3,"create_time": "2025-07-25T10:18:24"},"children": [{"comment": {"parent_id": 2,"comment_id": 3,"content": null,"level": null,"article_id": 1,"user_id": 4,"create_time": "2025-07-25T10:18:29"},"children": []}, {"comment": {"parent_id": 2,"comment_id": 4,"content": null,"level": null,"article_id": 1,"user_id": 5,"create_time": "2025-07-25T11:37:48"},"children": []}]}]
}]

还值得优化的地方:

1. 当文章评论很多的时候,查出全部评论会占用大量内存,可以分页查询

2.遍历所有评论寻找父评论的时间为o(n),可以用hash表降到o(1)

http://www.lryc.cn/news/599833.html

相关文章:

  • Class18卷积层的填充和步幅
  • 仙人掌cacti中的RCE案例
  • 【Python】一些PEP提案(四):scandir、类型约束,异步asyncawait
  • win11 使用adb 获取安卓系统日志
  • 黑马点评01 - 项目介绍 短信登录
  • RAG、Function Call、MCP技术笔记
  • HTML+CSS+JS快速入门
  • Jenkins中HTML文件显示样式问题解决方案
  • uniapp使用css实现进度条带动画过渡效果
  • Elasticsearch-ik分析器
  • 轮盘赌算法
  • C语言————原码 补码 反码 (试图讲清楚版)
  • 多智能体(Multi-agent)策略模式:思维链CoT和ReAct
  • Ubuntu 环境下创建并启动一个 MediaMTX 的 systemd 服务
  • 电科金仓新一代数据库一体机:以 “云数据库 - AI 版” 破局 AI 时代,三骏守护定义行业新标杆
  • 项目管理进阶——解读软件项目管理-项目阶段复盘会(通用模板)【附全文阅读】
  • 文心4.5开源之路:从封闭到开放的力量
  • ARM-I2C硬实现
  • linux-开机启动流程
  • 编程语言Java——核心技术篇(三)异常处理详解
  • 将本地项目推送到远程github仓库
  • 学习游戏制作记录(克隆技能)7.25
  • C语言|指针的应用
  • Python 之 keyboard
  • 详解软件需求中的外部接口需求
  • 网络安全入门第一课:信息收集实战手册(3)
  • 芯显15寸工控液晶屏RV150X0M-N10产品资料详情
  • 高德地图 loca 实现点线的显示和点击
  • Ping32:企业数据安全的智能护盾
  • C++中使用Essentia实现STFT/ISTFT