BBS项目之文章评论
需求分析
# 需求1
不许匿名用户评论,提供登录/注册的接口
# 需求2
可以评论别人的文章,也可以回复别人对自己文章的评论(即根评论与子评论)
# 需求3
评论的渲染方式有两种,点击评论按钮,使用DOM操作临时渲染评论楼;刷新URL,使用render渲染评论楼
# 需求4
给回复按钮绑定两个属性,当前根评论的用户,以及评论的主键值
数据库表设计
class Comment(models.Model):
"""评论表"""
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
content = models.CharField(verbose_name='评论内容', max_length=255)
comment_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
# 自关联
parent = models.ForeignKey(to='self', null=True) # 有些评论就是根评论
这里需要注意的是:
我们知道根评论与子评论的区别在于,子评论多了一个parent_id,因此评论表中的自关联字段parent必须设置null=True
,否则,所有的评论都是子评论,没有根评论。
代码
前端
{% if request.user.is_authenticated %}
<div>
<a href="#" style="text-decoration: none" title="发表评论"><img src="/static/img/comment.png" alt=""
style=" 20px;height: 20px"> 发表评论</a>
<div>
<div>
<span style="color: red" id="thanks"></span>
</div>
<textarea name="comment" id="id_comment" cols="60" rows="10" placeholder="支持Markdown"></textarea>
</div>
<button class="btn btn-primary" id="id_submit">提交评论</button>
<span style="color: red" id="error"></span>
</div>
{% else %}
<div>
<a href="{% url 'login' %}" style="text-decoration: none">登录</a>
<a href="#" class="register_model" style="text-decoration: none">注册</a>
</div>
{% endif %}
//设置一个全局的parentId
let parentId = null;
//用户点击评论按钮后直接朝后端发送ajax请求
$('#id_submit').on('click', function () {
let content = $('#id_comment').val();
//判断当前的评论是否为子评论,如果是去除 /n之前的字符
if (parentId) {
//利用切片操作(找到
的索引,然后利用切片,切片顾头不顾尾)
let indexNum = content.indexOf('
') + 1;
content = content.slice(indexNum); //将indexNum之前的所有数据切除,只保留后面的一部分
}
$.ajax({
url: '/comment/',
type: 'post',
data: {
'article_id': '{{ article_obj.pk }}',
'content': content,
'parent_id': parentId, //如果没有点击回复parentId就是Null
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
success: function (args) {
if (args.code === 1600) {
//将评论框的内容清空
$('#id_comment').val('');
//感谢回复
$('#thanks').html('感谢您的回复☺:');
//临时渲染评论楼
let username = '{{ request.user.username }}';
let temp = `
<a href='#' style="text-decoration: none;" title='发表评论'><img src="/static/img/comment.png" alt="" style=" 20px;height: 20px"> ${username}</a>
<div class="panel panel-info">
<div class="panel-body">
${content}
</div>
</div>`;
$('.content-group').append(temp);
//清空全局的parentId字段
parentId = null;
}
}
})
});
后端
def comment(request):
# 自己也可以给自己评论
if request.is_ajax():
back_dict = {'code': 1600, 'msg': ''}
if request.method == 'POST':
if request.user.is_authenticated:
article_id = request.POST.get('article_id')
content = request.POST.get('content')
# 获取父评论
parent_id = request.POST.get('parent_id')
# 直接操作评论表 存储数据 两张表
# 开事务
with transaction.atomic():
models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)
models.Comment.objects.create(user=request.user, article_id=article_id, content=content,
parent_id=parent_id)
back_dict['msg'] = '评论成功'
else:
back_dict['code'] = 1601
back_dict['msg'] = '用户未登录'
return JsonResponse(back_dict)