1,在文章模型中添加点赞字段,用多对多关系统计所有为文章点赞的用户。
class Article(BaseModel):
...
# 为文章点赞
users_like = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name="articles_like",
verbose_name='点赞',blank=True)
2,编写处理函数
我这里只接收了需要点赞的文章id这个参数,至于如何判断该请求是点赞还是取消赞,
则是从对应文章的users_like中查询,如果已有记录,说明点过赞,那就进行取消赞操作,如果没有记录。那就将当前用户添加到文章记录中,实现点赞操作,然后再返回当前操作类型和点赞数,供前端进行显示渲染。
class LikeArticle(View):
"""
点赞功能
"""
def get(self, request):
pass
def post(self, request):
try:
user = request.user
if user.is_authenticated:
article_id = request.POST.get('article_id')
article = Article.objects.filter(id=article_id)
if article.exists():
user_like = article[0].users_like.filter(id=user.id)
# 查询当前用户是否为当前文章点过赞
type = 1
if user_like.exists():
# 若点过,则取消
article[0].users_like.remove(user)
type = 0
else:
# 若无,则点赞
article[0].users_like.add(user)
like_sum = article[0].users_like.count()
return JsonResponse({'state': 200, 'type': type, 'like_sum': like_sum})
return JsonResponse({'state': 400, 'data': '点赞无效'})
except Exception as e:
return JsonResponse({'state': 500, 'data': f'出现异常:{e}'})
3,编写点赞路由
urlpatterns = [
...
# 为文章点赞
path(r'like_article/',
views.LikeArticle.as_view(),
name="like_article"),
]
4,前端页面部分
由于文章部分是由django模板语言渲染的,就不太好用vue再定义变量实现样式和点赞数的切换,
所以决定点赞按钮的初始化还是用django,只在点赞按钮上添加点击事件,
若点击,则会传递当前按钮节点和当前文章id到函数中。
{% if article.users_like.count > 0 %}
<el-button @click="ck_like($event,{{ article.pk }})"
icon="el-icon-caret-top" size="mini"
{% if user in article.users_like.all %}
type="primary"
{% else %}
plain
{% endif %}
>赞同 {{ article.users_like.count }}</el-button>
{% else %}
<el-button @click="ck_like($event,{{ article.pk }})"
icon="el-icon-caret-top" size="mini" plain>赞同</el-button>
{% endif %}
5,js部分
event.currentTarget这里实际上就是按钮的对象了,拿到id发送post请求,得到结果后
直接用js就能实现改变样式或者修改内部文字,达到局部刷新的效果。
ck_like(event,id){
let like_btn = event.currentTarget
var url = this.host+'/like_article/'
var data = {
'article_id': id,
}
$.ajax({
url: url,
type: 'post',
data: data,
success: function (res) {
// console.log(res)
if(res.state==200){
like_btn.children[1].textContent = '赞同 '+res.like_sum
if(res.type){
like_btn.className = 'el-button el-button--primary el-button--mini'
}else{
like_btn.className = 'el-button el-button--default el-button--mini is-plain'
}
}else {
index.$message.error({
message: res.data,
});
}
},
error: function (res){
index.$message.error({
message: res.data,
});
}
})
},