文章详情与点赞和评论
前端代码:
{% extends 'base.html' %}
{% block css %}
<style>
#div_digg {
float: right;
margin-bottom: 10px;
margin-right: 30px;
font-size: 12px;
width: 128px;
text-align: center;
margin-top: 10px;
}
.diggit {
float: left;
width: 46px;
height: 52px;
background: url('/static/img/upup.gif') no-repeat;
text-align: center;
cursor: pointer;
margin-top: 2px;
padding-top: 5px;
}
.buryit {
float: right;
margin-left: 20px;
width: 46px;
height: 52px;
background: url('/static/img/downdown.gif') no-repeat;
text-align: center;
cursor: pointer;
margin-top: 2px;
padding-top: 5px;
}
.clear {
clear: both;
}
.diggword {
margin-top: 5px;
margin-left: 0;
font-size: 12px;
color: #808080;
}
</style>
{% endblock %}
{% block content %}
<h2>{{ article_obj.title }}</h2>
<div>{{ article_obj.content|safe }}</div>
{# 点赞点踩前端样式渲染#}
<div class="clearfix">
<div id="div_digg">
<div class="diggit action">
<span class="diggnum" id="digg_count">{{ article_obj.up_num }}</span>
</div>
<div class="buryit action">
<span class="burynum" id="bury_count">{{ article_obj.down_num }}</span>
</div>
<div class="clear"></div>
<span style="color: red" id="info"></span>
</div>
</div>
{# 评论楼渲染#}
<div>
<p>评论列表</p>
{# #1楼 2018-04-11 23:03 最咸的咸鱼#}
<ul class="list-group">
{% for comment in comment_list %}
<li class="list-group-item">
<span>#{{ forloop.counter }}楼</span>
<span>{{ comment.create_time|date:'Y-m-d h:i:s' }}</span>
<span><a href="/{{ comment.user.username }}/">{{ comment.user.username }}</a></span>
<span><a class="pull-right reply" username="{{ comment.user.username }}" comment_id = "{{ comment.pk }}">回复</a></span>
<p>
{% if comment.parent_id %}
<p>@{{ comment.parent.user.username }}</p>
{% endif %}
{{ comment.content }}
</p>
</li>
{% endfor %}
</ul>
</div>
{# 渲染前端评论样式#}
{% if request.user.is_authenticated %}
<div>
<p>发表评论</p>
<p>
昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
value="{{ request.user.username }}">
</p>
<p>评论内容:</p>
<p><textarea name="comment" id="comment" cols="60" rows="10"></textarea></p>
<p>
<button class="btn btn-primary" id="submit">提交评论</button>
<span style="color: red" class="error"></span>
</p>
</div>
{% else %}
<a href="/login/">登录</a>
<a href="/register/">注册</a>
{% endif %}
{% endblock %}
{% block js %}
<script>
// 点赞点踩
$('.action').on('click', function () {
var $btn = $(this);
// 如何判断用户点的是赞还是踩
var isUp = $(this).hasClass('diggit');
$.ajax({
url: '/UpAndDown/', // 专门朝处理点赞点踩业务逻辑的后端视图函数提交请求
type: 'post',
data: {
'article_id': '{{ article_obj.pk }}',
'is_up': isUp,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success: function (data) {
if (data.code == 1000) {
$('#info').text(data.msg);
// 动态修改数字
var old_num = $btn.children().text();
$btn.children().text(Number(old_num) + 1) // 一定要转数字 才能做加减
} else {
$('#info').html(data.msg)
}
}
})
});
// 提交评论
// 先在全局定义一个变量
var commentId = null;
$('#submit').click(function () {
var conTent = $('#comment').val();
var conTent1 = $('#comment').val();
if(commentId){
// 找到\n所对应的索引
var indexN = conTent.indexOf('\n') + 1;
conTent = conTent.slice(indexN) // 将indexN前面所有的内容全部切掉 只保留后面的内容
}
$.ajax({
url:'/comment/',
type:'post',
data:{
'article_id':'{{ article_obj.pk }}',
'content':conTent,
'parent_id':commentId,
'csrfmiddlewaretoken':'{{ csrf_token }}'
},
success:function (data) {
if (data.code == 1000){
$('.error').text(data.msg);
$('#comment').val('');
// 用户提交评论之后 先用DOM操作临时渲染一个评论楼出来 当用户刷新页面的时候再按照统一的评论楼样式渲染
// 1 动态生成标签
var userName = '{{ request.user.username }}';
var temp = `
<li class="list-group-item">
<span><span class="glyphicon glyphicon-comment"></span><a href="/${userName}/">${userName}:</a></span>
<p>
${conTent1}
</p>
</li>
`;
// 2 将生成好的标签 添加到ul标签内
$('.list-group').append(temp);
// 清空全局变量 commmentId
commentId = null;
}
}
})
});
// 点击恢复按钮
$('.reply').click(function () {
// 不仅要获取评论的评论人用户名 还需要获取评论的主键值
var commentUserName = $(this).attr('username');
commentId = $(this).attr('comment_id'); // 给全局的commentId赋值
// 将信息写入textarea中 并自动聚焦
$('#comment').val('@'+commentUserName+'\n').focus()
})
</script>
{% endblock %}
后端代码:
def article_detail(request,username,article_id):
article_obj = models.Article.objects.filter(pk=article_id).first()
comment_list = models.Comment.objects.filter(article=article_obj)
return render(request,'article_detail.html',locals())
import json
from django.db.models import F
from django.utils.safestring import mark_safe
def UpAndDown(request):
if request.is_ajax():
if request.method == 'POST':
back_dic = {'code':1000,'msg':''}
# 1 判断当前用户是否登录
if request.user.is_authenticated():
article_id = request.POST.get('article_id')
is_up = request.POST.get('is_up') # true false
# print(is_up,type(is_up))
is_up = json.loads(is_up) # 将前端js数据格式的布尔值类型 转换成后端python格式的布尔值类型
# print(is_up, type(is_up))
# 2 判断当前文章是否是当前用户自己写的
article_obj = models.Article.objects.filter(pk=article_id).first()
if not article_obj.blog.userinfo == request.user:
# 3 校验当前用户是否已经点过了
is_click = models.UpAndDown.objects.filter(user=request.user,article=article_obj)
if not is_click:
# 4 操作数据库 更新记录
# 判断用户是点了赞 还是点了踩 从而决定到底给哪个普通字段加一
if is_up:
models.Article.objects.filter(pk=article_id).update(up_num = F('up_num') + 1)
back_dic['msg'] = '点赞成功'
else:
models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
back_dic['msg'] = '点踩成功'
# 真正的操作 点赞点踩表
models.UpAndDown.objects.create(user=request.user,article=article_obj,is_up=is_up)
else:
back_dic['code'] = 1001
back_dic['msg'] = '你已经点过了!'
else:
back_dic['code'] = 1002
back_dic['msg'] = '你个臭不要脸的,不能给自己点'
else:
back_dic['code'] = 1003
back_dic['msg'] = mark_safe('请先<a href="/login/">登录</a>')
return JsonResponse(back_dic)
from django.db import transaction
def comment(request):
if request.is_ajax():
if request.method == 'POST':
back_dic = {'code':1000,'msg':''}
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_dic['msg'] = '评论成功'
return JsonResponse(back_dic)