python嵌套评论实现

评论系统在一个博客中至关重要,是一个最直接的交流媒介。如何实现一个嵌套的评论呢?这里主要讨论嵌套的展示,评论数据提交部分比较简单,就略过。
首先,来看一张表,如下所示,其中我们最关注2个字段,一个是comment_id,另外一个是comment_parent,也就是说靠这两个字段定位父子关系,数据为0可以认为上面没有父节点了,否,则反。

mysql> SELECT comment_id,comment_post_id,comment_author,comment_author_email,comment_date,comment_parent FROM wp_comments WHERE comment_post_ID = 1 AND ( comment_approved = '1' OR ( comment_author = '回复2.2' AND comment_author_email = 'root@root.com' AND comment_approved = '0' ) ) ORDER BY comment_date_gmt;
+------------+-----------------+----------------+----------------------+---------------------+----------------+
| comment_id | comment_post_id | comment_author | comment_author_email | comment_date        | comment_parent |
+------------+-----------------+----------------+----------------------+---------------------+----------------+
|          1 |               1 | Mr WordPress   |                      | 2014-09-24 19:29:15 |              0 |
|         13 |               1 | 评论1          | test@test.com        | 2014-10-28 08:58:21 |              0 |
|         14 |               1 | 评论2          | test@test.com        | 2014-10-28 08:58:36 |              0 |
|         15 |               1 | 评论3          | test@test.com        | 2014-10-28 08:58:55 |              0 |
|         16 |               1 | 回复1          | root@root.com        | 2014-10-28 09:00:16 |             13 |
|         17 |               1 | 回复1.1        | root@root.com        | 2014-10-28 09:00:31 |             16 |
|         18 |               1 | 回复2          | root@root.com        | 2014-10-28 09:00:46 |             14 |
|         19 |               1 | 回复2.1        | root@root.com        | 2014-10-28 09:01:08 |             18 |
|         20 |               1 | 回复2.1.1      | root@root.com        | 2014-10-28 09:02:05 |             19 |
|         21 |               1 | 回复2.2        | root@root.com        | 2014-10-28 09:02:23 |             18 |
|         22 |               1 | 评论4          | root@root.com        | 2014-10-28 09:40:00 |              0 |
|         23 |               1 | 回复2.1.1.1    | root@root.com        | 2014-10-28 09:41:29 |             20 |
|         24 |               1 | 回复2.1.1.2    | test@test.com        | 2014-10-29 05:14:01 |             20 |
|         25 |               1 | 回复4          | test@test.com        | 2014-10-29 07:58:07 |             22 |
|         26 |               1 | abc啊嘎嘎       | test@test.com        | 2014-10-29 10:31:15 |              0 |
|         27 |               1 | 2.2.1          | root@root.com        | 2014-10-30 12:25:18 |             21 |
+------------+-----------------+----------------+----------------------+---------------------+----------------+
16 rows in set (0.00 sec)

然后,再次看这张表,发现其实这张表是一棵树的存放,不信,我把节点(comment_id跟comment_parent)摘下来,看看,比如,13的子节点有16,16的子节点是17,依次处理后,结果如下:

1
13 
 16
  17
14 
 18
  19
   20
    23
    24
  21
   27
15 
22
 25
26

所以,我们要写一段程序把上面的数据库出来的数据变成多叉树,这时候想到了json,json就很方便存放这些数据结构,然后出来一段代码如下:

#turn into json data 
dic={}
stack=[]
for c in comments:
    dic[c.comment_id]={'self':c,'level':0}
    if c.comment_parent!=0:
        if 'children' in dic[c.comment_parent]:
            dic[c.comment_parent]['children'].insert(0,dic[c.comment_id])
            pass
        else:
            dic[c.comment_parent]['children']=[dic[c.comment_id]]#{c.comment_id:c}
        dic[c.comment_id]['level']= dic[c.comment_parent]['level']+1
    else:
        stack.insert(0,dic[c.comment_id])

不过看不懂?没关系,慢慢看,继续看下面结果,你就懂的,这段程序输入的comments是:

[<Comments: 1>, <Comments: 13>, <Comments: 14>, <Comments: 15>, <Comments: 16>, <Comments: 17>, <Comments: 18>, <Comments: 19>, <Comments: 20>, <Comments: 21>, <Comments: 22>, <Comments: 23>, <Comments: 24>, <Comments: 25>, <Comments: 26>, <Comments: 27>]

输出的是stack变量,它的结果为:

[{'level': 0, 'self': <Comments: 26>},
 {'children': [{'level': 1, 'self': <Comments: 25>}],
  'level': 0,
  'self': <Comments: 22>},
 {'level': 0, 'self': <Comments: 15>},
 {'children': [{'children': [{'children': [{'level': 3,
                                            'self': <Comments: 27>}],
                              'level': 2,
                              'self': <Comments: 21>},
                             {'children': [{'children': [{'level': 4,
                                                          'self': <Comments: 24>},
                                                         {'level': 4,
                                                          'self': <Comments: 23>}],
                                            'level': 3,
                                            'self': <Comments: 20>}],
                              'level': 2,
                              'self': <Comments: 19>}],
                'level': 1,
                'self': <Comments: 18>}],
  'level': 0,
  'self': <Comments: 14>},
 {'children': [{'children': [{'level': 2, 'self': <Comments: 17>}],
                'level': 1,
                'self': <Comments: 16>}],
  'level': 0,
  'self': <Comments: 13>},
 {'level': 0, 'self': <Comments: 1>}]

仔细观察每一层输出的[HTML_REMOVED]最后一个数字,有没有发现树是倒过来了,这个没关系,就是要倒过来,后面遍历的时候使用栈操作,children是指下面的子节点,self是自身的comment,本level是层次,代码不细说了,自己看,接下来要用到上面的stack变量的结果作为下面程序的输入:

result=[]
while len(stack)>0:
    top=stack.pop()
    #result.append(top)
    if 'children' not in top:
        result.append((top['level'],top['self']) )
    else:
        c=top['children']
        l=top['level']
        s=top['self']
        result.append( (l,s))
        stack=stack+c
    pass

然后结果是这样,前面的数字就是level,就是缩进的层次,后面就是一个comment对象:

[(0, <Comments: 1>),
 (0, <Comments: 13>),
 (1, <Comments: 16>),
 (2, <Comments: 17>),
 (0, <Comments: 14>),
 (1, <Comments: 18>),
 (2, <Comments: 19>),
 (3, <Comments: 20>),
 (4, <Comments: 23>),
 (4, <Comments: 24>),
 (2, <Comments: 21>),
 (3, <Comments: 27>),
 (0, <Comments: 15>),
 (0, <Comments: 22>),
 (1, <Comments: 25>),
 (0, <Comments: 26>)]

最后,完成遍历,我们得到了层次信息,这样,在用css显示去控制层次就很方便了。本博客评论就是这么写的,有兴趣可以看看源码。
总结,利用类似json这样的数据结构,可以很好的把多叉树放入其中,然后利用栈遍历方法,把位置跟节点层次安顺序输出,方便展示。

  1. 测试下
  2. 这个参考下, 好牛逼
    1. 这个还好,后来又写了一下更精简了。
  3. 好奇这个嵌套评论是不是不限制嵌套层数的
  4. 参考了博主的思路,实现了博客的嵌套评论。源码中的方法比较简洁,谢谢博主。
  5. 更精致的那个是啥?
    1. 看我开源博客,本页面,最下方。
  6. 小E 你好NB啊 牛逼的牛 牛逼的逼!
  7. 最近也在学PHP了...可是没有太大动力...看来要去发掘些好玩的元素了
    1. 嗯,没事啊。慢慢学习不着急
  8. 没有智力活动迹象的评论001
    1. 提克,居然用这个马甲,以为我不认识你了。