Django第8章: 多级评论树

模拟实现流程

代码

// 传入的参数形式要求
comment_list = comment_list = [
    {'id': 1, 'content': '1111', 'parent_id': None, 'children_contents':[]},
    ...
]

// 转换成嵌套结果列表
def transform_list(comment_list):
    comment_dict = {}
    for d in comment_list:
        id = d.get('id')
        comment_dict[id] = d
    for k in comment_dict:
        parent_id = comment_dict[k]['parent_id']
        if parent_id:
            comment_dict[parent_id]['children_contents'].append(comment_dict[k])
    res_list = []
    for i in comment_dict:
        if not comment_dict[i]['parent_id']:
            res_list.append(comment_dict[i])
    return res_list

// 结果形式
res_list = [{
    'id': 8,
    'content': '8888',
    'parent_id': None,
    'children_contents': []
}, ...]
    

推倒过程

  1. 模拟取出某文章的所有评论的部分信息如下,

    comment_list = [
        {'id': 1, 'content': '1111', 'parent_id': None, 'children_contents': []},
        {'id': 2, 'content': '2222', 'parent_id': None, 'children_contents': []},
        {'id': 3, 'content': '3333', 'parent_id': 1, 'children_contents': []},
        {'id': 4, 'content': '4444', 'parent_id': 2, 'children_contents': []},
        {'id': 5, 'content': '5555', 'parent_id': 4, 'children_contents': []},
        {'id': 6, 'content': '6666', 'parent_id': 3, 'children_contents': []},
        {'id': 7, 'content': '7777', 'parent_id': 6, 'children_contents': []},
        {'id': 8, 'content': '8888', 'parent_id': None, 'children_contents': []},
    ]
  2. 进一步构建数据结构, {1: {‘id‘:1, ...}, 2: {‘id‘:2, ...},}
    comment_dict = {}
    
    for d in comment_list:
        id = d.get('id')
        comment_dict[id] = d
    
    '''
    {1: {'id': 1, 'content': '...', 'parent_id': None, 'children_contents': []},
    2: {'id': 2, 'content': '...', 'parent_id': None, 'children_contents': []},
    3: {'id': 3, 'content': '...', 'parent_id': 1, 'children_contents': []},
    4: {'id': 4, 'content': '...', 'parent_id': 1, 'children_contents': []},
    5: {'id': 5, 'content': '...', 'parent_id': 4, 'children_contents': []},
    6: {'id': 6, 'content': '...', 'parent_id': 3, 'children_contents': []},
    7: {'id': 7, 'content': '...', 'parent_id': 6, 'children_contents': []},
    8: {'id': 8, 'content': '...', 'parent_id': None, 'children_contents': []},
    }
  3. 若存在父评论将每个评论放进其parent_id对应的children_contents列表中
    for k in comment_dict:
        parent_id = comment_dict[k]['parent_id']
        if parent_id:
            comment_dict[parent_id]['children_contents'].append(comment_dict[k])
    
    '''
    {1: {'id': 1, 'content': '...', 'parent_id': None, 'children_contents': [
        {'id': 3, 'content': '...', 'parent_id': 1, 'children_contents': [],
        {'id': 4, 'content': '...', 'parent_id': 1, 'children_contents': []}
        ]},
    
    2: {'id': 2, 'content': '...', 'parent_id': None, 'children_contents': []},
    3: {'id': 3, 'content': '...', 'parent_id': 1, 'children_contents': [
        {'id': 6, 'content': '...', 'parent_id': 3, 'children_contents': []},
    ]},
    
    4: {'id': 4, 'content': '...', 'parent_id': 1, 'children_contents': [
        {'id': 5, 'content': '...', 'parent_id': 4, 'children_contents': []},
        ]},
    
    5: {'id': 5, 'content': '...', 'parent_id': 4, 'children_contents': []},
    6: {'id': 6, 'content': '...', 'parent_id': 3, 'children_contents': [
        {'id': 7, 'content': '...', 'parent_id': 6, 'children_contents': []},
    ]},
    
    7: {'id': 7, 'content': '...', 'parent_id': 6, 'children_contents': []},
    8: {'id': 8, 'content': '...', 'parent_id': None, 'children_contents': []},
    }
  4. 筛选出所有的根评论, 整理成列表形式
    res_list = []
    for i in comment_dict:
        if not comment_dict[i]['parent_id']:
            res_list.append(comment_dict[i])
    
    res_list = [
        {
        'id': 1,
        'content': '1111',
        'parent_id': None,
        'children_contents': [{
            'id': 3,
            'content': '3333',
            'parent_id': 1,
            'children_contents': [{
                'id': 6,
                'content': '6666',
                'parent_id': 3,
                'children_contents': [{
                    'id': 7,
                    'content': '7777',
                    'parent_id': 6,
                    'children_contents': []
                }]
            }]
        }]
    },
        {
        'id': 2,
        'content': '2222',
        'parent_id': None,
        'children_contents': [{
            'id': 4,
            'content': '4444',
            'parent_id': 2,
            'children_contents': [{
                'id': 5,
                'content': '5555',
                'parent_id': 4,
                'children_contents': []
            }]
        }]
    },
        {
        'id': 8,
        'content': '8888',
        'parent_id': None,
        'children_contents': []
    }]
  5. 遍历根评论(最关键)
    // 要实现的结构
        根评论1
            子评论1
            子评论1
    
        根评论2
            子评论3
            子评论4
    
        跟评论3
            子评论5
            子评论6
    
    // 实现函数
    def get_content(list):
        for d in list:
            print(d['content'])
            if d['children_contents']:
                # 递归,调用自身
                get_content(d['children_contents'])
    
    get_content(res_list)
    
    // 打印的结果
    1111
        3333
            6666
                7777
    2222
        4444
            5555
    
    8888

实现前端多级评论树

  1. 后端取到评论信息, 以[{}, {}]作为结果

    comment_list = article.comment_set.all().values('nid', 'content', 'parent_id_id')
    // 结构queryset[{'nid':1, 'content':'', 'parent_id_id': ''}, {...}, {...}, ...]
  2. 处理结果,达到转换参数要求
    for d in comment_list:
        d['children_contents'] = []
  3. 利用上面自定义的转换函数transform_list()转换,并将结果返回给前端ajax
    res_list = [{
    'id': 8,
    'content': '8888',
    'parent_id': None,
    'children_contents': []
    }, ...] 
  4. 前端页面代码
    <div class="blog_comment">
        <div class="comment_title">评论列表</div>
        <hr>
    
        <div class="list-group comment_form">
    
        </div>
    
        <script>
            // 处理函数,传入一系列评论根节点集合
            function comment_tree(comment_list) {
                var html = "";
    
                //  循环遍历根节点,内部参数为 索引 和 值
                $.each(comment_list, function (k, v) {
                    // 准备组合一个评论节点
                    var comment_item = '<div class="comment_item">';
    
                    // 构建评论内容
                    var temp = "<div class='content'><span>{0}{1}</span></div>".format(v['nid'], v['content']);
    
                    comment_item += temp;
    
                    // 判断内部是否有子评论,有子评论则取出来, 整合成<div class='content'>
                    if (v['children_contents']){
                        // 最关键的一步
                        comment_item += comment_tree(v['children_contents'])
                    }
                    // 最后闭合这个comment_item节点
                    comment_item += "</div>";
    
                    html += comment_item
                });
    
                return html
            }
    
            // 加载完毕触发ajax事件,再次向server发送请求, 接受处理好的评论列表
            $(function () {
                alert(1);
                $.ajax({
                    url: "",
                    type: 'GET',
                    success: function (data) {
    
                        // 将data从string解析成原来的列表结构
                        var my_comment_list = JSON.parse(data);
                        s = comment_tree(my_comment_list);
                        $('.comment_form').append(s)
                    }
                })
            });
    
        </script>
    
    </div>

ajax实现评论

// 标签
<div id="add-form" class="comment_con"><span class="comment_title">提交评论</span>
    <textarea id="comment_input" cols="30" rows="10" >
    </textarea>

    <p>
       <input type="button" value="submit" id="comment_submit_btn" class="btn btn-success">
    </p>
</div>

<script>
var parent_comment_id = "";  // 设置全局变量,当点击回复按钮则赋值为点击的评论的id;
var father_comment_username = ''; // 设置父级标签的全局变量,同样是点击回复按钮则设置对应的值;
var father_comment_content = '';

// 回复评论事件
$('.comment_list').on('click', '.reply_btn', function () {
    // 1.取出该条评论的id值,即为class属性值, 定位到父级标签后,就可以取出父级评论的内容;
    parent_comment_id = $(this).next().attr('class');

    // 2.点击回复按钮, 则设置father_comment_username的值;
    father_comment_username = $(this).siblings().eq(0).text();

    // 3.给文本框添加回复的用户名内容, 仅用于在前端显示, 注意此处使用text()赋值会出现问题;
    $('#comment_input').val('@'+father_comment_username+'\n');

    // 取出该评论的内容供后面使用
    father_comment_content = $(this).siblings().eq(4).children().eq(1).text();});

    // 文章点赞;
    $('#favor_btn').click(function () {
        {% if request.user.is_authenticated %}
             $.ajax({
            url:'/blog/favor/',
            type: 'post',
            data: {'article_id':{{ article.nid }}, 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
            success: function (data) {
                if(data.status=='success'){
                    $('#article_num').text(data.poll_num)
                }
            }});
        {% else %}
            window.location.href='/login?path='+$('#request_path').val();
        {% endif %}});

// 增加文章评论
  $("#comment_submit_btn").click(function () {
      // 1. 取出换行符 \n 的索引位置
      var index=$("#comment_input").val().indexOf("\n");

      // 2. 取出真正的文本内容,字符串切片,js语法,从第二行开始,切片所有的内容
      var comment_content=$("#comment_input").val().substr(index+1);
      alert(comment_content);

      {% if request.user.is_authenticated %}
        $.ajax({
           url:"/blog/comment/",
           type:"post",
           data:{"csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val(),
                 "article_id":{{ article.nid }},
                 "comment_content":comment_content,
                 "parent_comment_id":parent_comment_id
           },
           success:function (data) {
                // 判断是否是通过回复按钮来添加评论的,注意必须在最后清空father_comment_username这个变量
               var temp=father_comment_username;
               s='<li class="list-group-item comment_item"><a href="">{0}</a><a href="">{1}</a><a href="" class="pull-right">&nbsp;支持</a><a href="#comment_content" class="pull-right reply_btn">回复</a><span class="{2}"></span> <div> <span>{3}</span> <p>{4}</p></div> </li>';
               if (temp){father_comment_username="<a>@</a>"+temp}

               // js中利用字符串拼接
               s=s.format('{{ request.user.username }}',
                        data.comment_createTime,
                        parent_comment_id,
                        father_comment_username,
                        comment_content);

               $(".comment_list").append(s);
               $("#comment_input").val("");

               // 关键点, 每次走完此处必须对全局变量清零
               father_comment_username="";
               parent_comment_id=0;
               father_comment_content=''
        }
   });

      {% else %}
       location.href="/login?path={{ request.path }}";
      {% endif %}
  });

</script>

// views.py
def user_comment(request):
    """方法1, 直接在前端操作评论内容"""
    user_id = request.user.nid
    article_id = request.POST.get("article_id")
    comment_content = request.POST.get("comment_content").strip()
    # 若评论内容为空,则不添加任何信息
    if not comment_content:
        return HttpResponse('noy ok')

    # 1. 查看是否是通过回复(有父评论)发送还是直接评论发送
    if request.POST.get("parent_comment_id"):
        # 2. 获取该评论的父级评论id并保存记录
        c = int(request.POST.get("parent_comment_id"))
        comment_obj = Comment.objects.create(article_id=article_id, content=comment_content, user_id=user_id,
                                             parent_id_id=c)
    else:
        comment_obj = Comment.objects.create(article_id=article_id, content=comment_content, user_id=user_id)

    from django.db.models import F
    # 3. 对评论数量自加操作
    Article.objects.filter(nid=article_id).update(comment_num=F("comment_num") + 1)

    # 只传输创建时间过去
    response_ajax = {"comment_createTime": str(comment_obj.create_time)[:16], }  # 很关键,不去毫秒!
    return HttpResponse(json.dumps(response_ajax), content_type='application/json')

原文地址:https://www.cnblogs.com/fqh202/p/8734605.html

时间: 2024-10-23 21:24:56

Django第8章: 多级评论树的相关文章

Django 项目试炼blog(8) -- 评论树的显示

Views def get_tree_data(request): article_id = request.GET.get('article_id') send_data = list(Comment.objects.filter(article_id=article_id).values('pk','content','parent_comment_id')) return JsonResponse(send_data,safe=False) ORM生成的的是queryset对象,而非真正的

Django多级评论

一.原理 #多级评论原理简单原理,弄完之后发现基础白学了 msg_list = [ {'id':1,'content':'xxx','parent_id':None}, {'id':2,'content':'xxx','parent_id':None}, {'id':3,'content':'xxx','parent_id':None}, {'id':4,'content':'xxx','parent_id':1}, {'id':5,'content':'xxx','parent_id':4},

day20 project+查看新闻列表 + 点赞 + 图片验证码 + 评论和多级评论 + 后台管理 + webSocket + kindEditor

Day20回顾: 1. 请求生命周期 2. 中间件 md = [ "file_path.classname" ] process_request[可有可无] process_response[必须有] process_request process_response process_request process_response process_request process_response process_request process_response 路由->函数 3.

扩展JS格式化(Format)功能及评论树

1.JS格式化功能 <script>         /*         1. 调用对象方法时,通过调用类的prototype中的方法,可以扩展         2. 正则表达式 /\w+/g         3. 字符串replace                 ''.replace('alex','sb');                 ''.replace(/\w+/,'sb');                 ''.replace(/\w+/g,'sb');        

多级目录树

前台: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <

基于bootstrup的jQuery多级列表树

bootstrap-treeview是一款效果非常酷的基于bootstrup的jQuery多级列表树插件.该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一些继承树结构,如视图树.列表树等等. 在线演示:http://www.htmleaf.com/Demo/201502141380.html 下载地址:http://www.htmleaf.com/jQuery/Menu-Navigation/201502141379.html

《啊哈!算法》第7章 神奇的树

第3节 堆排序 把n个元素建立一个堆,首先将这n个结点以自顶向下.从左到右的方式从1到n编码,这样可以把n个结点转换成一颗完全二叉树 紧接着从最后一个非叶子结点(结点编号为n/2)开始到根节点(结点编号为1),逐个扫描所有结点,根据需要将当前结点向下调整,直到以当前结点为根结点的子树符合堆的特性. #include <iostream> #include <vector> #include <algorithm> using namespace std; //向下调整函

jQuery和CSS3动感手风琴多级列表树菜单

mtree.js是一款效果非常炫酷的jQuery和CSS3动感手风琴多级列表树菜单插件.该手风琴多级列表树菜单基于velocity.js和CSS3 transitions来制作.它提供了5种主题样式的手风琴列表树菜单效果.这5种主题分别为:bubba,skinny,transit,jet,nix. 效果演示:http://www.htmleaf.com/Demo/201505251902.html 下载地址:http://www.htmleaf.com/jQuery/Menu-Navigatio

基于bootstrap的jQuery多级列表树插件

http://www.cnblogs.com/mfc-itblog/p/5233453.html http://www.htmleaf.com/jQuery/Menu-Navigation/201502141379.html http://www.htmleaf.com/Demo/201502141380.html 简要教程 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件.该jQuery插件基于Twitter Bootstrap,以简单和