实现层级评论

实现层级评论

1. 预热

写一个函数,输入整数n,能够输出斐波那契数列中第n个的值。

2. 分析层级评论

从现象分析:

我们可以把每一条评论抽象为字母,为了方便识别,我们约定首层评论为A,B , C,D之类不带数字的字母。

ABCD的直接子评论为A1,A2,B1,B2之类的。A1 A2,B1, B2的子评论为A1-1, A1-2,B1-1,B1-2。。A1-1的子评论为A1-1-1,A1-1-2等等以此类推

那么我们可以简单的抽象出一个例子,类似这样:

我们的每个post的评论列表是一个queryset,类似如下:

<QuerySet [<Comment: A>, <Comment: A1>, <Comment: A2>, <Comment: A1-1>, <Comment: A2-1>, <Comment: A1-1-1>, <Comment: A2-1-1>, <Comment: B>, <Comment: B1>, <Comment: A1-1-2>, <Comment: B2>, <Comment: C>]>

现在问题转换为,如何将上面这样的queryset显示成上图中的层级关系。

进一步分析发现,上图中的层级关系如果用python的字典来表示,可以表示为:

{

A : {A1:{A1-1:{A1-1-1:{},A1-1-2:{}}}, A2:{A2-1:{A2-1-1:{}}}},

B: {B1: {}, B2: {}},

C: {}

}

每一行其实可以找到一对关系:当前节点和父节点的关系,比如第一行父节点为None,子节点为A。第二行父节点为A,子节点为A1.那么上图的关系可以转换为一个列表:

[(None, A),

(A, A1),

(A1, A1-1),

(A1-1, A1-1-1),

(A1-1, A1-1-2),

(A,A2),(A2, A2-1),

(A2-1,A2-1-1),

(None,B),

(B, B1),

(B,B2),

(None,C)]

我们的评论列表,每个评论对象都包含自己的父评论,即存在这样一种关系(comment_obj.parent_comment, comment_obj),那么我们可以把评论的queryset转换为类似上面的列表。如果可以找到把上面列表转换为层级显示的字典的话,即可以实现我们评论列表queryset的层级评论显示。

基本思路:

创建一个空字典,用来保存将评论列表转换为评论字典的结果。

如果一个评论没有父节点,那么将这个评论作为根节点,存如评论字典。如果有父节点,那么递归去查找父节点,如果找到了父节点,将自己插入父节点下面。正确生成评论字典之后,再对字典进行递归输出即可。我们将输出字典的函数自定义为一个simple_tag,方便我们在前端调用。

代码如下:

from django.utils.safestring import mark_safe
# 递归查找父节点
def find_father(dic, comment_obj):
    # 对字典中的每一组元素进行循环操作
    for k, v_dic in dic.items():
        # 如果k等于comment_obj的父节点,那么表示找到了父亲。
        if k == comment_obj.parent_comment:
            # 找到了父亲,认祖归宗,把自己归位到父亲下面,并给将来的儿子留个位置
            dic[k][comment_obj] = {}
            # 找到了父亲,处理完毕,返回
        else:
            # 刚才没找到,剥一层,接着往下找。
            find_father(dic[k], comment_obj)


# 递归生成html字符串
def generate_comment_html(sub_comment_dic, margin_left_val):
    # 先创建一个空字符串
    html = ""
    # 对传入的字典进行循环操作
    for k, v_dic in sub_comment_dic.items():
        html += "<div style='margin-left:%spx'><span class='nickname'>" % margin_left_val + k.name + "</span>" + "<time class='submit-date'>" + str(k.created_time.strftime('%Y-%m-%d %H:%M:%S')) + "<div class='text'>" + k.text + '</div></div><hr>'
        # html += "<div style='margin-left:%spx' class='comment-node'>" % margin_left_val + k.text + "</div>"
        # 有可能v_dic中依然有元素, 递归继续加
        if v_dic:
            html += generate_comment_html(v_dic, margin_left_val+35)
    # 循环完成最后返回html
    return html


# 生成层级评论
@register.simple_tag
def build_comment_tree(comment_list):
    # 定义一个空字典用来保存转换之后的结果
    comment_dic = {}
    # 对comment_list中的每个元素进行循环
    for comment_obj in comment_list:
        # 判断comment_obj是否存在父节点。如果没有,这把该评论作为第一个节点
        if comment_obj.parent_comment is None:
            comment_dic[comment_obj] = {}
        else:
            # 否则去找该对象的父节点。
            find_father(comment_dic, comment_obj)

    # 上面执行完毕,comment_dic中会有转换好的结果
    # 开始拼接html字符串
    html = "<ul class='comment-list list-unstyled'>"
    # 规定一个margin left,每次有递归的时候就往右缩进一点。
    margin_left = 0
    # 对comment_dic中的每一组元素进行操作
    for k,v in comment_dic.items():
        # 第一层html
        html += "<li class='comment-item'><span class='nickname'>" + k.name + "</span>" + "<time class='submit-date'>" + str(k.created_time.strftime('%Y-%m-%d %H:%M:%S')) + "<div class='text'>" + k.text + '</div></li>'
        # 通过递归把他的儿子加上
        html += generate_comment_html(v, margin_left+35)
    # 最后把ul关上
    html += " </ul>"
    # 关掉转义
    return mark_safe(html)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值