一、表结构
class UserInfo(models.Model): """用户表""" username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.CharField(max_length=32,null=True) def __str__(self): return self.username class NewsCategory(models.Model): """新闻类型表""" caption = models.CharField(max_length=16) def __str__(self): return self.caption class NewsInfo(models.Model): """新闻表""" title = models.CharField(max_length=32,verbose_name="标题") summary = models.CharField(max_length=255,verbose_name="简介",null=True) url = models.CharField(max_length=255,verbose_name="URL",null=True) avatar = models.CharField(max_length=255,verbose_name="文章配图",null=True) ctime = models.DateTimeField(auto_now_add=True,verbose_name='创建时间') category = models.ForeignKey(to="NewsCategory",verbose_name="类别") author = models.ForeignKey(to="UserInfo",verbose_name="作者") # 点赞和评论时,记着更新like_count,comment_count。自增1/自减1: F 实现 like_count = models.IntegerField(default=0) comment_count = models.IntegerField(default=0) def __str__(self): return self.title class Comment(models.Model): """评论记录表""" content = models.CharField(max_length=255,verbose_name="评论内容") user = models.ForeignKey(to="UserInfo",verbose_name="评论者") news = models.ForeignKey(to="NewsInfo",verbose_name="评论的文章") ctime = models.DateTimeField(auto_now_add=True,verbose_name='评论时间') """多级评论需要 自关联""" parent = models.ForeignKey("Comment",related_name="pid",null=True,blank=True) def __str__(self): return self.content class Like(models.Model): """点赞记录表""" user = models.ForeignKey(to="UserInfo",verbose_name="点赞者") news = models.ForeignKey(to="NewsInfo",verbose_name="点赞的文章") ctime = models.DateTimeField(auto_now_add=True,verbose_name="点赞时间") # 建立联合唯一索引,限定每个用户给每篇文章只能点赞一次 class Meta: unique_together = [ ('user','news'), ]
二、相关数据结构
1. 从数据库读出的数据: [ {'id': 1, 'user': 'alex', 'content': '灌我鸟事', 'parent_id': None}, {'id': 2, 'user': 'alex', 'content': '管我鸟事', 'parent_id': None}, {'id': 3, 'user': 'eric', 'content': '你个文盲', 'parent_id': 1}, {'id': 4, 'user': 'egon', 'content': '好羡慕你们这些没脸的人呀', 'parent_id': 2}, {'id': 5, 'user': 'alex', 'content': '你是流氓', 'parent_id': 3}, {'id': 6, 'user': 'alvin', 'content': '双击666', 'parent_id': 5}, {'id': 7, 'user': 'alex', 'content': '智障啊 ->_->', 'parent_id': 6}, {'id': 8, 'user': 'alex', 'content': '你冷酷无情', 'parent_id': 4}, {'id': 9, 'user': 'eric', 'content': '你无理取闹', 'parent_id': 4}, {'id': 10, 'user': 'standby', 'content': '赶紧买个瓜围观', 'parent_id': 8}, {'id': 11, 'user': 'cindy', 'content': '前排卖水了啊', 'parent_id': 10}, {'id': 12, 'user': 'egon', 'content': '一群土老帽...', 'parent_id': None}, ] 2. 需要构造成如下结构: [ { 'parent_id': None, 'id': 1, 'content': '灌我鸟事', 'children': [ { 'parent_id': 1, 'id': 3, 'content': '你个文盲', 'children': [ { 'parent_id': 3, 'id': 5, 'content': '你是流氓', 'children': [ { 'parent_id': 5, 'id': 6, 'content': '双击666', 'children': [ { 'parent_id': 6, 'id': 7, 'content': '智障啊->_->', 'children': [ ], 'user': 'alex' } ], 'user': 'alvin' } ], 'user': 'alex' } ], 'user': 'eric' } ], 'user': 'alex' }, { 'parent_id': None, 'id': 2, 'content': '管我鸟事', 'children': [ { 'parent_id': 2, 'id': 4, 'content': '好羡慕你们这些没脸的人呀', 'children': [ { 'parent_id': 4, 'id': 8, 'content': '你冷酷无情', 'children': [ { 'parent_id': 8, 'id': 10, 'content': '赶紧买个瓜围观', 'children': [ { 'parent_id': 10, 'id': 11, 'content': '前排卖水了啊', 'children': [ ], 'user': 'cindy' } ], 'user': 'standby' } ], 'user': 'alex' }, { 'parent_id': 4, 'id': 9, 'content': '你无理取闹', 'children': [ ], 'user': 'eric' } ], 'user': 'egon' } ], 'user': 'alex' }, { 'parent_id': None, 'id': 12, 'content': '一群土老帽...', 'children': [ ], 'user': 'egon' } ] 3. 最后拼接HTML,返回给前端进行展示
三、代码实现
def format_comments2(li): dic = {} for item in li: item["children"] = [] dic[item["id"]] = item result = [] for item in li: pid = item['parent_id'] if pid: dic[item["parent_id"]]["children"].append(item) else: result.append(item) return result def build_comments_tree2(result): tpl = """ <div class="item"> <div class="title">{0}:{1} <a href="">回复</a></div> <div class="body">{2}</div> </div> """ html = "" """递归遍历所有子评论""" for item in result: if not item["children"]: html += tpl.format(item["user"],item["content"],"") else: html += tpl.format(item["user"],item["content"],get_comment_tree(item["children"])) return html def format_comments(comment_list): """ 把相关评论的列表集合转换成如下的格式 方便在build_comments_tree里构造HTML 也可以在后端把构造好的列表传递给前端 用js来构造HTML [ { 'id':comment_id, 'content':'具体评论内容', 'user':'评论人', 'parent_id':id/None, 'children':[ {}, {}, ... ] }, ... } """ formated_list = [] tmp_list = [] for comment in comment_list: cid = comment['id'] pid = comment.get('parent_id') dic = {'id': cid, 'user': comment['user'], 'content': comment['content'], 'parent_id': pid, 'children': []} tmp_list.append(dic) if not pid: formated_list.append(dic) else: for item in tmp_list: if item['id'] == pid: item['children'].append(dic) break return formated_list def build_comments_tree(formated_list): tpl = """ <div class="item"> <div class="comment">{0}:{1}<a href="" class="reply">回复</a></div> <div class="body">{2}</div> </div> """ html = "" """深度优先搜索:递归遍历所有子评论""" for item in formated_list: children = item.get('children') if children: html += tpl.format(item['user'], item['content'], build_comments_tree(children)) else: html += tpl.format(item['user'],item['content'],"") return html def comment_tree(request): comment_list = [ {'id': 1, 'user': 'alex', 'content': '灌我鸟事', 'parent_id': None}, {'id': 2, 'user': 'alex', 'content': '管我鸟事', 'parent_id': None}, {'id': 3, 'user': 'eric', 'content': '你个文盲', 'parent_id': 1}, {'id': 4, 'user': 'egon', 'content': '好羡慕你们这些没脸的人呀', 'parent_id': 2}, {'id': 5, 'user': 'alex', 'content': '你是流氓', 'parent_id': 3}, {'id': 6, 'user': 'alvin', 'content': '双击666', 'parent_id': 5}, {'id': 7, 'user': 'alex', 'content': '智障啊 ->_->', 'parent_id': 6}, {'id': 8, 'user': 'alex', 'content': '你冷酷无情', 'parent_id': 4}, {'id': 9, 'user': 'eric', 'content': '你无理取闹', 'parent_id': 4}, {'id': 10, 'user': 'standby', 'content': '赶紧买个瓜围观', 'parent_id': 8}, {'id': 11, 'user': 'cindy', 'content': '前排卖水了啊', 'parent_id': 10}, {'id': 12, 'user': 'egon', 'content': '一群土老帽...', 'parent_id': None}, ] # result = format_comments2(li) # html = build_comments_tree2(result) result = format_comments(comment_list) html = build_comments_tree(result) return render(request,'demo.html',{'html':html})
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .body{ margin-left: 30px; } .be_hidden { display: none; } </style> </head> <body> <h1>所有评论</h1> {{ html|safe }} <script src="{% static "js/bootstrap.min.js" %}"></script> <script src="{% static "js/jquery-3.2.1.min.js" %}"></script> <script> $(function () { $('.comment').click(function () { if ($(this).next().hasClass('be_hidden')){ $(this).next().removeClass('be_hidden') }else{ $(this).next().addClass('be_hidden') } }) }) </script> </body> </html>