# data=[
#     [11,22,33],
#     [44,55,66]
# ]
# data[0].append(data[1])
# print(data)
# data[1].append(77)
#
# 由于[11, 22, 33, [44, 55, 66, 77]]和[[11, 22, 33, [44, 55, 66, 77]], [44, 55, 66, 77]]
#
# 引用的是同一块内存地址,所以谁添加了内容对应的也跟随添加


# data=[
#       {'k1':'v1'},
#       {'k2':'v2'}
#       ]
#
# for item in data:
#     item['kk']='vv'
#
#
# # python里面列表和字典引用的是引用类型,当我们拿到地址被操作了,会发生级联变化;如果想要再独立一份就需要copy()
#
# 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},
#    {'id':6,'content':'xxx','parent_id':2},
#    {'id':7,'content':'xxx','parent_id':5},
#    {'id':8,'content':'xxx','parent_id':3},
# ]
# # v=[row.setdefault('child')  for row in msg_list]
# #
# # #注意列表生成公式里面 不能出现=等赋值操作,可以使用方法
# # print(msg_list)
#
# #方式2
#
# msg_list_dict={}
# # msg_list_dict={
# # 1, {'id':1,'content':'xxx','parent_id':None},
# # 2, {'id':2,'content':'xxx','parent_id':None},
# #               }
# #字典的在存储的时候,键会转换成一个hashs值,这个hash值和内存地址相关,# 无论字典里的键值对有多大,都可以一次的寻找到key对应的value
# #字典查询就是数据库里的hansh 索引,直接拿到key就可以快得惊人的获取到value
# #无需向列表那样 查询 是 一个个顺序 遍历
#
# #所以定义一个字典 方便我们查找 评论信息,而且因为Python是数据引用类型,相同数据引用一块内存,也不会占用内存
# for item in msg_list:
#     item['child']=[]
#     msg_list[item['id']]=item
#
# #程序运行到此处,会有两个msg_list   msg_list_dict
# ret=[]
# for item in  msg_list:
#     pid=item['parent_id']
#     if pid:
#         msg_list[pid]['child'].apend(item)
#     else:
#         ret.append(item)

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},
    {'id':6,'content':'xxx','parent_id':2},
    {'id':7,'content':'xxx','parent_id':5},
    {'id':8,'content':'xxx','parent_id':3},
]
msg_dict={}

#1、给所以 评论设置一个 child键=[空列表的值] [row.setdefault('child',[]) for row in msg_list] 列表生成器方法

#3、定义一个查询用的字典
for item in msg_list:
    item['child']=[]
    msg_dict[item['id']]=item



#2、把带有'parent_id'的键的字典,添加到对应的父字典里(你会想到再次遍历msg_list,但是多层循环效率低下,于是重新定义一个字典)
for item in msg_list:
    pid=item['parent_id']
    if pid:
        msg_dict[pid]['child'].append(item)


# 4、找出根评论·
root_coment=[]
for item in msg_list:
    if not item['parent_id']:
        root_coment.append(item)

for item in  root_coment:
    print(item)

 

模板

    '''   
    <div class="cooment">
        <div class="content"></div>  根评论
            <div class="cooment">
                <div class="content"></div> 子评论
                <div class="content"></div> 子评论
                <div class="content"></div> 子评论
             </div>  
        <div class="content"></div> 根评论
            <div class="cooment">
                <div class="content"></div> 子评论
                <div class="content"></div> 子评论
                <div class="content"></div> 子评论
             </div>  
        <div class="content"></div>  根评论
        <div class="content"></div>
    </div>    
    '''
    #----------------------------------------------
    comment_str=''
    comment_str += '<div class="comment">'
    for row in result:
        tp1='<div class="content">%s</div>'% (row['content'])
        comment_str+=tp1

        if row['child']:
            for chil in row['child']:
                comment_str += '<div class="comment">'
                tp1 = '<div class="content">%s</div>' % (chil['content'])
                comment_str += tp1
            comment_str += '</div>'


    comment_str += '</div>'
    return render(request,'comment.html',locals())

 

多级评论之博客园结构版

思路

1、评论区和评论展示区域

  <form action="/comment/" method="post" novalidate>
        {% csrf_token %}
        {{ obj.content }} <span id="errors"></span>                                                  评论展示区域
        <p>
            <input type="button" value="发表" class="btn btn-primary ajax_comment">                   评论发表区域
        </p>
    </form>

2、评论在评论发表区域属于之后使用ajax提交到server存储数据库

<script>
        $('.ajax_comment').click(function () {
            {#           由于评论内容前缀携带@父评论\n,所以需要 找到'\n'的字符串索引进行截断#}
            var $index = $('[name="content"]').val().indexOf('\n')
            var $content = $('[name="content"]').val().substr($index + 1)
            var $csrf = $("[name='csrfmiddlewaretoken']").val();
            var $article_id = {{ artic.nid }};

            var formdata = new FormData();
            formdata.append('csrfmiddlewaretoken', $csrf)
            formdata.append('content', $content)
            formdata.append('article_id', $article_id)
            formdata.append('parent_id_id', $prant_comment_id)
            {% if request.user.is_authenticated %}
                $.ajax({
                    url: '/comment/',
                    type: 'post',
                    data: formdata,
                    processData: false,
                    contentType: false,
                    success: function (data) {

 

3、server存储完成后,把成功消息回传浏览器

def comment(request):
    responses={'flag':True,'msg':None}
    obj=Commenform(request.POST)
    if obj.is_valid():
        content=obj.cleaned_data['content']
        article_id=request.POST.get('article_id')
        user_id=request.user.nid
        parent_id_id=request.POST.get('parent_id_id',)
        comment_obj=models.Comment.objects.create(article_id=article_id,
                                      content=content,
                                      parent_id_id=parent_id_id,
                                      user_id=user_id,
                                      )
        responses['create_time']=str(comment_obj.create_time)[:16]
        models.Article.objects.filter(nid=article_id).update(
                                comment_count=F('comment_count')+1)
    else:
        responses['flag']=False
        responses['msg']=obj.errors
    return HttpResponse(json.dumps(responses))

 

4、此时数据库中已有数据,通过页面刷新即可获得最新评论,可是体验不佳,于是浏览器可以通过 server端回传的信号,使用JavaScript或jQuery动态添加评论标签,制造显示效果;

if (data['flag']) {
                            var $create_time = data['create_time'];
                            var $content = $('[name="content"]').val();
                            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>'
                            s = s.format(
                                '{{ request.user.username }}',
                                $create_time,
                                $prant_comment_id,
                                $fathercomment_username,
                                $content
                            );

                            $('.comment_list').append(s)
                            $('[name="content"]').val(' ');
                            $prant_comment_id = '';
                            $fathercomment_username = '';


                        }
                        else {
                            $.each(data['msg'], function (i, j) {
                                $('#errors').text(j[0]).css('color', 'red')
                                setTimeout(function () {
                                    $("#errors").text("")
                                }, 1000)


                            })
                        }
                    }

                })
View Code

 

5、根评论搞定(对文章的评论),可是如果涉及对评论进行评论呢?利用A标签的锚特效, 当用户点击回复的A标签,同样锚定到评论区域‘’

 6、于此同时 给回复A标签绑定其他事件,携带 父级评论的ID、内容

 <script>
        var $prant_comment_id = '';
        var $fathercomment_username = '';
        $(".comment_list").on("click", "#reply_btn", function () {
            var $fathercomment_username = $(this).siblings().eq(0).text()
            $('#comment_content').val('@' + $fathercomment_username + '\n')
            $prant_comment_id = $(this).siblings().eq(3).attr('name')


        })
    </script>

7.示意图 

8.Golang实现

在Go语言中复杂的数据类型需要使用Struct进行数据封装;

appList := make([]*AppInfo, 0)
type AppInfo struct {
    pname    string
    name     string
    children []*AppInfo  //也需要设置为指针类型
}

但是结构体属于值类型,如果需要对[]切片中结构体进行修改需要使用指针类型

package main

import (
    "fmt"
    "strings"
)

type AppInfo struct {
    pname    string
    name     string
    children []*AppInfo
}

func (this *AppInfo) AddChidren(child *AppInfo) {
    this.children = append(this.children, child)
}

// 通过Map的key唯一的特性过滤重复元素
func RemoveDuplicate(applist []*AppInfo) []*AppInfo {
    result := []*AppInfo{}
    tempMap := make(map[string]bool)
    for _, app := range applist {
        if ok := tempMap[app.name]; !ok {
            result = append(result, app)
            tempMap[app.name] = true
        }
    }
    return result
}

func makeTree(applicationList []string) {
    /*
       security/webaduit/http-proxy
       security/LogProxy/日志审计采集器
    */
    appList := make([]*AppInfo, 0)
    appMap := make(map[string]*AppInfo, 0)
    //组织树形结构
    for _, appInfo := range applicationList {
        splitedList := strings.Split(appInfo, "/")
        rootName := splitedList[0]
        parentName := splitedList[1]
        name := splitedList[2]
        children := []*AppInfo{}
        rootRow := &AppInfo{"", rootName, children}
        parentRow := &AppInfo{rootName, parentName, children}
        currentRow := &AppInfo{parentName, name, children}
        appList = append(appList, rootRow, parentRow, currentRow)
    }
    //去重
    appList = RemoveDuplicate(appList)
    //建立查询索引
    for _, app := range appList {
        appMap[app.name] = app
    }
    //组织树形结构
    for _, currentApp := range appList {
        //获取当前App的父亲节点
        pname := currentApp.pname
        if pname != "" {
            //从查询appMap 中查询到当前APP的父级是谁?
            prantApp := appMap[pname]
            //把当前App信息追加到当前APP父级的childList
            prantApp.AddChidren(currentApp)
        }

    }
    //展示组织好的树形结构
    for _, app1 := range appList {
        if app1.pname == "" {
            fmt.Println("---------level1---", app1.name)
            for _, app2 := range app1.children {
                fmt.Println("---------level2-----", app2.name)
                for _, app3 := range app2.children {
                    fmt.Println("---------level3---------", app3.name)
                }
            }

        }
    }

}
func main() {
    treeData := []string{"北京/朝阳/CBD", "北京/海淀/西二旗"}
    makeTree(treeData)
}

 

posted on 2017-09-10 19:42  Martin8866  阅读(1020)  评论(0编辑  收藏  举报