django实现多级评论
实现原理:
在页面加载完成后,jQuery调用initComments()函数,initComments()函数会向后端发起Ajax请求,后端收到请求后,会把所有评论的数据以JSON格式返回到前端,然后前端再把评论的数据在页面上进行展示,评论的层级关系通过父级id来进行识别。
首先来看一下评论的表结构:
# 评论表 class Comment(models.Model): # 要评论哪篇文章,外键指向文章表 comment_which_article = models.ForeignKey(to='Article', on_delete=models.CASCADE, verbose_name='评论的文章', related_name='comment') # 评论内容,任意内容 comment_content = models.TextField(verbose_name='评论内容') # 父级评论,指向评论表自己 # 如果父级评论为空,则为一级评论,否则为子级评论,可以有多级 parent_comment = models.ForeignKey(to="self", on_delete=models.CASCADE, related_name='son_comment', null=True, blank=True, verbose_name="父级评论") def __str__(self): return self.comment_content
然后看一下HTML页面的内容:
首先准备一个显示评论的区域:
<!-- 此处是将要展示评论内容的区域 --> <!-- 先放一个div,作为评论的显示div块 --> <div id="comment_div"> <!-- ul部分才是真正要展示评论的区域 --> <!-- 评论将以列表的样式进行显示,先在这里放一个<ul>标签,拿到评论数据后,直接在<ul>下面添加<li>即可 --> <!-- 设置id="comment_list",供后面选择标签时使用 --> <ul id="comment_list"> <!-- 后面的评论以<li>的样式放在此处 --> </ul> </div>
当页面加载完成后,调用 initComments() 函数向后端发起请求:
// 页面加载完成后执行的操作 // 页面加载完成后,向后端发起请求,请求评论的数据 $(function (){ initComments(); });
再看看后端的视图如何给前端返回JSON数据:
from django.http import JsonResponse # 收到Ajax请求后的处理函数:comment() def comment(request): # 首先,获取到前端传过来的文章ID【article_id】, 才知道是那一篇文章的评论 article_id = request.GET.get('article_id') ''' 找到这篇文章下的所有评论数据; 以前都是获取到一个querySet,也就是类似一个列表,里面放了每一个评论数据的object对象; 但是这里,使用了.values()方法,获取到的数据将是下面这样的: [ {'id': 1, 'comment_which_article_id': 1, 'comment_content': '31232', 'parent_comment_id': None}, {'id': 2,'comment_which_article_id': 1,'comment_content': '123123123213','parent_comment_id': None}, {'id': 3, 'comment_which_article_id': 1, 'comment_content': '49831743141', 'parent_comment_id': 1}, {'id': 4, 'comment_which_article_id': 1, 'comment_content': '917491739491', 'parent_comment_id': 3}, {'id': 5, 'comment_which_article_id': 1, 'comment_content': '12313213213', 'parent_comment_id': 2}, {'id': 6, 'comment_which_article_id': 1, 'comment_content': '21321321321', 'parent_comment_id': 4} ] 这样的数据看似是一个列表,但是实际上还是一个querySet对象,因此将它转换成列表list(); 所以最后得到的comments,就是一个列表,列表的样子就是上面的数据的样子。 ''' comments = list(Comment.objects.filter(comment_which_article=article_id).values()) # 使用JsonResponse,将comments以JSON的形式返回给前端 # 这里必须加上safe=False,如果不加的话, 就会报错【具体为什么,我还没搞懂】 return JsonResponse(comments, safe=False)
最后看看这个前端的函数initComments() , 它向后端请求数据,并把数据在页面进行展示:
// initComments函数 function initComments() { // 通过jQuery的$.ajax({}) 向后端发送Ajax异步请求 $.ajax({ // 请求的路径是comment // 将文章的id传到后端,才能通过id获取到评论的数据 url: '/comment/?article_id={{ articleDetail.pk }}', // 请求的方法为:GET方法 type: 'GET', // 接受的返回的数据格式为:JSON格式 dataType: 'JSON', // 回调函数,请求成功后执行的操作 // 参数data,用于接收后端返回的JSON数据 success: function(data){ console.log(data); /* * $.each,循环遍历data数据,每循环一次,拿到数据的索引index和数据的值item, * item就是每一条数据,即:{'id': 1, 'comment_which_article_id': 1, 'comment_content': '31232', 'parent_comment_id': None} * */ $.each(data, function(index, item){ /* * 这里的变量 li,就是将要添加到已经准备好的<ul>标签中的<li>标签,其实就是评论的内容 * * $("<li>"): * 创建一个<li>标签 * * .attr('id', "id_" + item.id): * 将这个<li>标签的id属性值设置为 "id_" + item.id,【其中item.id就是评论自己的id值】 * * .append($('<a href="#">').text(item.comment_content)): * 在这个<li>标签里面再创建一个<a>标签,<a>标签的内容就是要显示的评论内容 * 【.text(item.comment_content):就是设置<a>标签的内容为评论的内容content】 * * .append($('<ul>')): * 由于每一条评论下面可能还有子评论,所以又在每一个<li>标签里面创建一个空的<ul>标签,用于放它的子评论 * * */ var li = $("<li>").attr('id', "id_" + item.id).append($('<a href="#">').text(item.comment_content)).append($('<ul>')); // 判断一下,如果没有父级评论,那就是一级评论 // 直接展示就可以了 if (!item.parent_comment_id){ // $('#comment_list').append(li): 展示一级评论 // 找到前面已经准备好的,id=comment_list的<ul>标签 // .append(li):在<ul>标签里面添加上面的 li $('#comment_list').append(li); }else { // else: 如果有父级评论,那就是子级评论 // 那就在父级评论对应的<li>下面的<ul>中添加 li // $("#id_" + item.parent_comment_id):找到父级评论对应的<li> // $("#id_" + item.parent_comment_id).children('ul'):找到父级评论对应的<li>里面的<ul> // .append(li):在找到的这个<ul>里面添加 li $("#id_" + item.parent_comment_id).children('ul').append(li); } }) } }) } </script>
效果:
前端接收到的数据:
页面的显示效果:
附言:
这只是一个多级评论展示的简单示例而已,并不完善,实际上多级目录,关系层级都可以这样来实现。