实现django评论树使用了三种方式
第一支种方式通过递归实现
缺点:每次查找parent_id的时候都要在ret所有的元素里面找一遍,找不到再在元素的children中寻找,一直找到为止
comment_list = [ {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None}, {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None}, {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None}, {'id': 4, 'content': '你最牛逼', 'user': '大王', 'parent_id': 1}, {'id': 5, 'content': '我最牛逼', 'user': '张三', 'parent_id': 1}, {'id': 6, 'content': '你最牛逼', 'user': '李四', 'parent_id': 4}, {'id': 7, 'content': '你们都是垃圾...', 'user': '王老五', 'parent_id': 2}, {'id': 8, 'content': '给我点赞哦...', 'user': '赵老六', 'parent_id': 3}, {'id': 9, 'content': '什么东西啊...', 'user': '小李', 'parent_id': 8}, {'id': 10, 'content': '见到你女友,交定你朋友...', 'user': '张三', 'parent_id': None}, {'id': 11, 'content': '大家好,我是大胖...', 'user': '李四', 'parent_id': 6}, ] #评论列表的生成 #第一种方式基本递归,缺点每次查找都需要在ret所有的元素都找一遍,找不到在从儿子里面找一遍 #在在不到在在孙子里面找一遍,知道找到为止。重复寻找。 class Node: comment_list = [ {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None}, {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None}, {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None}, {'id': 4, 'content': '你最牛逼', 'user': '大王', 'parent_id': 1}, {'id': 5, 'content': '我最牛逼', 'user': '张三', 'parent_id': 1}, {'id': 6, 'content': '你最牛逼', 'user': '李四', 'parent_id': 4}, {'id': 7, 'content': '你们都是垃圾...', 'user': '王老五', 'parent_id': 2}, {'id': 8, 'content': '给我点赞哦...', 'user': '赵老六', 'parent_id': 3}, {'id': 9, 'content': '什么东西啊...', 'user': '小李', 'parent_id': 8}, {'id': 10, 'content': '见到你女友,交定你朋友...', 'user': '张三', 'parent_id': None}, {'id': 11, 'content': '大家好,我是大胖...', 'user': '李四', 'parent_id': 6}, ] #递归 def digui(ret,row): for rt in ret: if rt['id'] == row['parent_id']: row['children'] =[] rt['children'].append(row) return #ret= [ # {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None,'children';[ # {'id': 4, 'content': '你最牛逼', 'user': '大王', 'parent_id': 1}, # {'id': 5, 'content': '我最牛逼', 'user': '张三', 'parent_id': 1}, # ]}, # {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None,'children';[]}, # {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None,'children';[]}, # ] # {'id': 6, 'content': '你最牛逼', 'user': '李四', 'parent_id': 4}, else: Node.digui(rt['children'],row) # @property def create_tree(self,comment_list): ret = [] for row in comment_list: if not row['parent_id']: # None row['children'] = [] ret.append(row) # [ # {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None,'children';[]}, # {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None,'children';[]}, # {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None,'children';[]}, # ] else:#是回复的某个评论 #for i in ret: # if row['parent_id'] == i['id']: # i['children'].append(row) #二级评论实现 # else: # 找三层 Node.digui(ret,row) return ret #第一种执行 # print(Node().create_tree(comment_list))
第二种方式通过列表和字典的引用方式查找
缺点是查找的复杂度没有第一种多,但是每次找parent_id还是需要comment_list中全部找一遍,并且还有在comment_list中添加元素,在ret中引用第一层的元素会增加内存的消耗。
#第二种查找方式,字典列表的引用方式 comment_list = [ {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None}, {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None}, {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None}, {'id': 4, 'content': '你最牛逼', 'user': '大王', 'parent_id': 1}, {'id': 5, 'content': '我最牛逼', 'user': '张三', 'parent_id': 1}, {'id': 6, 'content': '你最牛逼', 'user': '李四', 'parent_id': 4}, {'id': 7, 'content': '你们都是垃圾...', 'user': '王老五', 'parent_id': 2}, {'id': 8, 'content': '给我点赞哦...', 'user': '赵老六', 'parent_id': 3}, {'id': 9, 'content': '什么东西啊...', 'user': '小李', 'parent_id': 8}, {'id': 10, 'content': '见到你女友,交定你朋友...', 'user': '张三', 'parent_id': None}, {'id': 11, 'content': '大家好,我是大胖...', 'user': '李四', 'parent_id': 6}, ] ret = [] for row in comment_list: row.update({'children':[]}) for item in comment_list: current_row = item current_row_parent_id = current_row['parent_id'] if not current_row_parent_id: ret.append(item) else: for r in comment_list: if r['id'] == current_row_parent_id: r['children'].append(item) #把有parent_id的数据加入到comment_list对应ID的chilren列表中 #而不是加入到rent中,因为是引用型ret中指向的内存地址是一致的 #缺点,当有不为空的parent_id的元素时,需要找comment_list中找一遍和parent_id相等的ID值,效率比递归的comment_list自身 #和子元素都找一遍的效率高,还有在comment_list中添加元素,在ret中引用第一层的元素会增加内存的消耗。 # print(ret) # print(comment_list)
第三中方式基于hash查找
基于字典的查找方式
#第三种基于哈希查找,字典存储时会调用Python内部散列函数,将键(Key)作为参数进行转换,得到一个唯一的一个地址,然后将值 #存入这个地址中,所字典的查找也是基于哈希的,所以查找很快速 comment_list = [ {'id': 1, 'content': 'Python最牛逼', 'user': '小李', 'parent_id': None}, {'id': 2, 'content': 'Java最牛逼', 'user': '小李', 'parent_id': None}, {'id': 3, 'content': 'PHP最牛逼', 'user': '小李', 'parent_id': None}, {'id': 4, 'content': '你最牛逼', 'user': '大王', 'parent_id': 1}, {'id': 5, 'content': '我最牛逼', 'user': '张三', 'parent_id': 1}, {'id': 6, 'content': '你最牛逼', 'user': '李四', 'parent_id': 4}, {'id': 7, 'content': '你们都是垃圾...', 'user': '王老五', 'parent_id': 2}, {'id': 8, 'content': '给我点赞哦...', 'user': '赵老六', 'parent_id': 3}, {'id': 9, 'content': '什么东西啊...', 'user': '小李', 'parent_id': 8}, {'id': 10, 'content': '见到你女友,交定你朋友...', 'user': '张三', 'parent_id': None}, {'id': 11, 'content': '大家好,我是大胖...', 'user': '李四', 'parent_id': 6}, ] #创建字典 ret = [] comment_list_dict = {} for row in comment_list: row.update({'children':[]}) comment_list_dict[row['id']] = row print(comment_list_dict) for item in comment_list: parent_row = comment_list_dict.get(item['parent_id']) if not parent_row: ret.append(item) else: parent_row['children'].append(item) print(ret)
回归前端,使用simple_tag
返回的数据为一个处理好的字典,回归给前端的时候使用自定义模板标签,在Html中调用直接使用模板方法使用
#__author: Administrator #date: 2016/12/26 from django import template from django.utils.safestring import mark_safe register = template.Library() def diGui(children_list): html = "" for cv in children_list: b = '<div class="comment-box"><span>' b += cv['content'] + "</span>" b += diGui(cv['children']) b += "</div>" html += b return html @register.simple_tag def create_tree(comment_list): html = '<div class="comment-list">' for v in comment_list: a = '<div class="comment-box"><span>' a += v['content'] + "</span>" a += diGui(v['children']) a += "</div>" html += a return mark_safe(html) """ function diGui(children_list){ var html = ""; $.each(children_list,function (ck,cv) { var b = '<div class="comment-box"><span>'; b+= cv.content + "</span>"; b += diGui(cv.children); b += "</div>"; html += b; }); return html; } function create_tree(data,$this) { var html = '<div class="comment-list">'; $.each(data,function (k,v) { var a = '<div class="comment-box"><span>'; a+= v.content + "</span>"; // 创建自评论 a += diGui(v.children); a+= "</div>"; html += a; }); html += "</div>"; $this.after(html); } """
{% load laogao %} {% create_tree comment_tree %} <style> .comment-box{ margin-left: 20px; } </style>
人生苦短,我用cnblog