多级评论的实现思路

 

一、表结构

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>

 

四、前端展示

 

转载于:https://www.cnblogs.com/standby/p/7823013.html

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值