django博客项目-文章评论功能

实现流程

根评论:基于文章的评论
子评论:对于评论的评论
两者区别:是否有父评论
对评论进行树形显示。

构建样式

代码

前端代码:

<div class="clearfix">
    <div id="div_digg">
        {% csrf_token %}
        <div class="diggit action">
            <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color: red;"></div>
    </div>
</div>


<div class="comments">
    <p>发表评论</p>
    <p>
        <p>昵称: <input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
    </p>
    <p>评论内容:</p>
    <textarea name="" id="" cols="60" rows="10"></textarea>
    <p><button class="btn btn-default comment_btn">提交评论</button></p>
</div>

效果展示

在这里插入图片描述

根评论提交和render显示

render显示,在用户提交评论后,点击刷新页面后显示所有根评论的内容。
发送请求到article_detail 视图函数中会返回数据库中所有评论数据,再进行页面渲染。

代码

前端代码

<div class="comments">
    <p>评论列表</p>

    <ul class="comment_list">
        {% for comment in comment_list %}
        <li class="list-group-item">
            <div>
                <a href=""># {{ forloop.counter }}</a>&nbsp;&nbsp;
                <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                <a href=""><span>{{ comment.user.username }}</span></a>
                <a href="" class="pull-right">回复</a>
            </div>
            <div class="comment_con">
                <p>{{ comment.content }}</p>
            </div>
        </li>
        {% endfor %}
    </ul>

    <p>发表评论</p>
    <p>
        <p>昵称: <input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
    </p>
    <p>评论内容:</p>
    <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
    <p><button class="btn btn-default comment_btn">提交评论</button></p>
</div>

<script>
    // 评论
    $(".comment_btn").click(function (){
        var pid = ""
        var content = $("#comment_content").val()
        $.ajax({
            url:"/comment/",
            type:"post",
            data:{
                "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                "article_id": {{ article_obj.pk }},
                "content": content,
                "pid": pid
            },
            success: function(data) {
                console.log(data)
                // 清空输入评论框
                $("#comment_content").val("")
            }
        })
    })
</script>
{% endblock %}

后端代码:

def article_detail(request, username, article_id):
    user = UserInfo.objects.filter(username=username).first()
    article_obj = models.Article.objects.filter(pk=article_id).first()
    blog = models.Blog.objects.filter(userinfo__username=username).first()

    comment_list = models.Comment.objects.filter(article_id=article_id)

    return render(request, 'article_detail.html', locals())

def comment(request):
    print(request.POST)
    article_id = request.POST.get('article_id')
    pid = request.POST.get('pid')
    content = request.POST.get('content')
    user_id = request.user.pk

    models.Comment.objects.create(
        user_id=user_id,
        article_id=article_id,
        content=content,
        parent_comment_id=pid
    )

    return HttpResponse('ok')

效果展示

在这里插入图片描述

ajax显示根评论

用户点击提交评论后,评论内容应局部刷新到评论列表。

代码

前端代码:
<script>
    // 评论
    $(".comment_btn").click(function (){
        var pid = ""
        var content = $("#comment_content").val()
        $.ajax({
            url:"/comment/",
            type:"post",
            data:{
                "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                "article_id": {{ article_obj.pk }},
                "content": content,
                "pid": pid
            },
            success: function(data) {
                console.log(data)
                var create_time = data.create_time
                var username = data.username
                var content = data.content

                s = `
                <li class="list-group-item">
                    <div>
                        <span>${create_time}</span>&nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>
                `
                $(".comment_list").append(s)

                // 清空输入评论框
                $("#comment_content").val("")
            }
        })
    })
</script>

后端代码:

def comment(request):
    print(request.POST)
    article_id = request.POST.get('article_id')
    pid = request.POST.get('pid')
    content = request.POST.get('content')
    user_id = request.user.pk


    # 事务操作
    with transaction.atomic():
        commnet_obj = models.Comment.objects.create(
            user_id=user_id,
            article_id=article_id,
            content=content,
            parent_comment_id=pid
        )
        # 数据同步
        models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)

    response = {}

    response['create_time'] = commnet_obj.create_time
    response['username'] = request.user.username
    response['content'] = commnet_obj.content

    return JsonResponse(response)

效果展示

在这里插入图片描述

回复按钮事件绑定

在用户点击某一个评论后的回复按钮时,光标应跳转到评论内容的输入框中,并且输入框里的第一行内容为**@该条评论的发布者名字**。

代码

为回复按钮添加一个username属性,就可以直接拿到该条评论的作者是谁。
<a class="pull-right reply_btn" username="{{ comment.user.username }}">回复</a>

<script>
    // 评论回复
    $(".reply_btn").click(function (){
        var val = "@" + $(this).attr("username") + "\n"
        // 焦点到输入框
        $('#comment_content').focus();
        $('#comment_content').val(val);
    })
</script>

效果展示

在这里插入图片描述

子评论提交和render方式显示子评论

代码

前端代码

    <ul class="comment_list">
        {% for comment in comment_list %}
        <li class="list-group-item">
            <div>
                <a href=""># {{ forloop.counter }}</a>&nbsp;&nbsp;
                <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                <a href=""><span>{{ comment.user.username }}</span></a>
                <a class="pull-right reply_btn" username="{{ comment.user.username }}" comment_pk="{{ comment.pk }}">回复</a>
            </div>

            {% if comment.parent_comment_id %}
                <div class="pid_info well">
                    <p>
                        {{ comment.parent_comment.user.username }}:{{ comment.parent_comment.content }}
                    </p>
                </div>
            {% endif %}

            <div class="comment_con">
                <p>{{ comment.content }}</p>
            </div>
        </li>
        {% endfor %}
    </ul>

<script>
    // 评论
    var pid = ""
    $(".comment_btn").click(function (){

        var content = $("#comment_content").val()
        if (pid){
            // 子评论,对content内容截断第一行
            var index = content.indexOf('\n')
            content = content.slice(index+1)
        }
        $.ajax({
            url:"/comment/",
            type:"post",
            data:{
                "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                "article_id": {{ article_obj.pk }},
                "content": content,
                "pid": pid
            },
            success: function(data) {
                console.log(data)
                var create_time = data.create_time
                var username = data.username
                var content = data.content

                s = `
                <li class="list-group-item">
                    <div>
                        <span>${create_time}</span>&nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>
                `
                $(".comment_list").append(s)

                // 清空输入评论框
                $("#comment_content").val("")

                // 清空pid
                pid=""
            }
        })
    })
</script>

评论的评论树显示

思路:

  1. 添加ajax事件,当页面刷新的时候向后台发送请求获取当前文章的所有数据
  2. 先将根评论添加到界面
  3. 再将子评论添加到根评论的下面
    关键的是如何找到其根评论,在每一个评论的标签中都有一个comment_id的属性,这样就可以找到其对应父评论的将子评论append到父评论下即可。

代码

前端代码:

    <p class="tree_btn">评论树</p>
    <div class="comment_tree">

    </div>
    <script>
<!--            // 评论树-->
        $.ajax({
            url:"/get_comment_tree/",
            type:"get",
            data:{
                "article_id":"{{ article_obj.pk }}"
            },
            success: function(data){
                console.log(data)
                $.each(data, function(index, comment_obj){
                    var pk = comment_obj.pk
                    var content = comment_obj.content
                    var parent_comment_id = comment_obj.parent_comment_id
                    var s = `<div class="comment_item" comment_id="${pk}">
                                    <p>${content}</p>
                                 </div>`

                    if (!parent_comment_id){
                        // 根评论处理
                        $(".tree_btn").append(s)
                    }
                    else{
                        $("[comment_id="+parent_comment_id+"]").append(s)
                    }
                })
            }
        })
    </script>

css样式

.comment_item{
    margin-left: 20px;
}

后端代码:

def get_comment_tree(request):
    article_id = request.GET.get("article_id")
    ret = list(models.Comment.objects.filter(article_id=article_id).values("pk", "content", "parent_comment_id"))

    return JsonResponse(ret, safe=False)

效果展示

在这里插入图片描述

新评论邮件通知作者

有评论的时候,将评论信息以邮件的方式通知到作者。新建一个线程来进行发送邮件,防止防落带宽延迟导致评论信息刷新慢。

代码

def comment(request):
    print(request.POST)
    article_id = request.POST.get('article_id')
    pid = request.POST.get('pid')
    content = request.POST.get('content')
    user_id = request.user.pk


    # 事务操作
    with transaction.atomic():
        commnet_obj = models.Comment.objects.create(
            user_id=user_id,
            article_id=article_id,
            content=content,
            parent_comment_id=pid
        )
        # 数据同步
        models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)

    response = {}

    response['create_time'] = commnet_obj.create_time
    response['username'] = request.user.username
    response['content'] = commnet_obj.content

    # 发送邮件
    article_obj = models.Article.objects.filter(pk=article_id).first()

    t = threading.Thread(target=send_mail, args=(
                                            "您的文章{0}新增一条评论内容".format(article_obj.title),
                                            content,
                                            settings.EMAIL_HOST_USER,
                                            ['282470196@qq.com'],)
    )
    t.start()

    return JsonResponse(response)

settings.py

# 邮件配置
EMAIL_HOST = 'smtp.exmail.qq.com'  # 163改成smtp.163.com
EMAIL_PORT = 465
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USER_SSL = True
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值