django---展示多级评论

发布时间 2023-12-10 00:46:51作者: 映辉

实现原理:

在页面加载完成后,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>

  

效果:

前端接收到的数据:

 页面的显示效果:

 

 

附言:

这只是一个多级评论展示的简单示例而已,并不完善,实际上多级目录,关系层级都可以这样来实现。