一、表结构
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>
四、前端展示