渲染评论
当我们打开文章详细页时,能够看到一条条的已有评论,这里我们先模仿博客园,采用评论楼的方式(如下)

后端数据
def article_detail(request, username, article_id):
article_obj = models.Article.objects.filter(pk=article_id).first()
comment_list = models.Comment.objects.filter(article_id=article_id)
return render(request, "blog/article_detail.html", {"username": username, "article_obj": article_obj, "comment_list": comment_list})
通过文章id取到该文章的所有评论
前端页面渲染
<div class="comment_show">
<p>评论楼:</p>
<ul class="comment_list list-group">
{% for comment in comment_list %}
<li class="comment_item list-group-item">
<div class="row">
<div class="col-md-offset-1">
<a>#{{ forloop.counter }}楼</a>
<span>{{ comment.create_time|date:'Y-m-d H:i' }}</span>
<span>{{ comment.user.username }}</span>
<div class="pull-right"><a class="reply-btn" comment_id="{{ comment.pk }}"
comment_user="{{ comment.user.username }}">回复</a></div>
</div>
</div>
{% if comment.parent_comment_id %}
<div class="row">
<div class="col-md-offset-1 parent_comment_info well">
<a>@{{ comment.parent_comment.user.username }}</a>
<span>{{ comment.parent_comment.content }}</span>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-md-offset-1">
<p>
{{ comment.content }}
</p>
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
为了区别根评论和子评论,在前端页面中需要做判断
评论框
评论内容是显示在文章详细页内的,所以前端页面部分仍然写在文章详细页内
首先要有一个给用户输入评论的评论框
<div class="comment clearfix">
<p>
昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
value="{{ request.user.nickname }}">
</p>
<label for="comment_area">评论内容</label>
<p>
<textarea name="" id="comment_area" cols="60" rows="10"></textarea>
</p>
<input type="button" value="提交" class="btn btn-default" id="comment_submit_btn">
</div>
这里的评论框我们使用textarea标签
提交评论事件
当用户在评论框输入内容后,点击提交按钮,我们使用ajax提交用户的评论内容
这里分为两种情况,用户提交的是根评论还是子评论
如果是子评论,我们应该通过点击每一条评论的回复来进行评论,这里我们需要给这个回复绑定一个点击事件
该点击事件要做到2个效果:
1.在评论框中聚焦
2.生成@用户名的内容
// 绑定回复按钮事件
var parent_comment_pk = "";
$(".comment_item .reply-btn").click(function () {
// 获取焦点
$("#comment_area").focus();
// 设置 @用户名
var val = "@" + $(this).attr("comment_user") + "
";
$("#comment_area").val(val);
//获取回复评论的主键值parent_comment_pk
parent_comment_pk = $(this).attr("comment_id")
})
这里的聚焦我们采用focus()功能,而@用户名内容我们采用拼接的方式生成,可以看到在前端页面上我们为了方便取到被评论的用户以及父评论id,我们给回复的标签设置两条自定义属性
comment_id="{{ comment.pk }}" comment_user="{{ comment.user.username }}"
提交按钮事件
// 提交评论事件
$("#comment_submit_btn").click(function () {
// parent_comment_pk区分根评论和子评论
if (parent_comment_pk) {
// 子评论
var content = $("#comment_area").val();
var index = content.indexOf("
");
content = content.slice(index + 1)
} else {
// 根评论
var content = $("#comment_area").val();
}
// 清空输入框的内容
$("#comment_area").val("");
$.ajax({
url: "/blog/comment/",
type: "post",
data: {
"content": content,
"article_id": "{{ article_obj.pk }}",
"csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
"pid": parent_comment_pk
},
success: function (data) {
var data = JSON.parse(data);
var count = data.split(",")[0];
var create_time = data.split(",")[1];
var s = '<li class="comment_item list-group-item"><div class="row"><div class="col-md-offset-1"> <a>#'+ count +'楼</a> <span>'+ create_time +'</span> <span>'+ '{{ request.user.username }}' + '</span> </div> </div> <div class="row"><div class="col-md-offset-1"><p>'+ content +'</p> </div> </div> </li>';
$(".comment_list").append(s)
}
})
});
通过上面的事件,我们可以看到我们通过声明了一个parent_comment_pk的变量,如果点击了回复按钮就给他附上父评论的id值,没有点击他则为空
在点击提交按钮时,通过他的值来判断该评论是根评论还是子评论
当点击完后,我们还要在页面不刷新时就看到自己的评论,这里通过ajax的回调函数实现
后端处理
def comment(request):
content = request.POST.get("content")
article_id = request.POST.get("article_id")
user_id = request.user.nid
pid = request.POST.get("pid")
with transaction.atomic():
if pid: # 子评论
comment = models.Comment.objects.create(content=content, article_id=article_id, user_id=user_id,
parent_comment_id=pid)
else: # 根评论
comment = models.Comment.objects.create(content=content, article_id=article_id, user_id=user_id)
models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
count = models.Comment.objects.filter(article_id=article_id).count()
create_time = str(comment.create_time)[:16]
response = str(count) + "," + create_time
return HttpResponse(json.dumps(response))
通过前端传来的pid值来判断该评论是根评论还是子评论,再将评论的数据写入数据库
为了方便前端的实时显示,我们在这里取到了评论生成的时间和评论数传给前端
