Django模型无法保存AJAX请求数据:点赞计数更新失败
Django点赞计数器无法更新数据库问题解决
问题描述
我是Ajax和Django新手,代码若有混乱还请见谅。我在尝试实现基础的点赞、点踩计数器时遇到问题:尽管前端发送了请求到view.py的likePost函数,但Django模型的like_votes字段始终无法更新,数据库中的点赞值无法保存。
现有代码
模型代码(models.py)
class Post(models.Model): post_text = models.CharField(max_length=1000) pub_date = models.DateTimeField('date published') like_votes = models.IntegerField(default=0) dislike_votes = models.IntegerField(default=0) def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) def __str__(self): return self.post_text
AJAX代码(前端模板)
<script type="text/javascript"> var likebtn = document.getElementById("likebtn"); likebtn.addEventListener('click', buttonClikckHandler); var num1 = 1; var like = parseInt("{{post.like_votes}}"); var new_l = like; function buttonClikckHandler() { console.log("clicked like"); const xhr = new XMLHttpRequest(); var new_l = like + num1 % 2; num1 = num1 + 1; document.getElementById("like").innerHTML = new_l; var catid; catid = $(this).attr("data-catid"); $.ajax({ type: "GET", url: "/likepost", data: { post_id: catid , votes : new_l }, success: function (data) { $('#like' + catid).remove(); $('#message').text(data); } }) console.log(new_l, num1); } </script>
视图代码(views.py)
def likePost(request ): if request.method == 'POST': post_id = request.POST['post_id'] print( post_id) likedpost = Post.objects.get(pk=post_id) likedpost.like_votes = int(request.POST['votes']) likedpost.save() return HttpResponse("Success!") else: return HttpResponse("Request method is not a POST")
问题分析
- 请求方法不匹配:前端AJAX用
GET请求,但视图只处理POST请求,导致每次请求都进入else分支,未执行数据库更新逻辑。 - 前端计算逻辑不合理:前端自行计算点赞数并传给后端,易出现数据不一致,且未考虑并发场景下的竞争问题。
- 缺少CSRF令牌:Django默认拦截无CSRF令牌的POST请求,这是新手常忽略的安全机制。
- 数据更新逻辑有风险:视图直接用前端传来的值覆盖数据库字段,未保障数据准确性与并发安全。
修复方案
修改AJAX代码
<script type="text/javascript"> var likebtn = document.getElementById("likebtn"); likebtn.addEventListener('click', buttonClikckHandler); function buttonClikckHandler() { console.log("clicked like"); const catid = this.getAttribute("data-catid"); $.ajax({ type: "POST", url: "/likepost", data: { post_id: catid, csrfmiddlewaretoken: "{{ csrf_token }}" // 添加CSRF令牌通过验证 }, success: function (response) { // 用后端返回的最新值更新页面,保障数据一致性 document.getElementById("like").innerHTML = response.like_votes; $('#message').text("点赞成功!"); }, error: function(xhr) { $('#message').text("操作失败:" + xhr.responseText); } }); } </script>
修改视图代码
from django.db.models import F from django.http import JsonResponse def likePost(request): if request.method == 'POST': post_id = request.POST.get('post_id') if not post_id: return JsonResponse({'error': '缺少帖子ID参数'}, status=400) try: likedpost = Post.objects.get(pk=post_id) # 使用F表达式执行原子更新,避免并发点赞导致的数据覆盖 likedpost.like_votes = F('like_votes') + 1 likedpost.save() # 刷新对象获取最新数据库值 likedpost.refresh_from_db() return JsonResponse({'like_votes': likedpost.like_votes}) except Post.DoesNotExist: return JsonResponse({'error': '该帖子不存在'}, status=404) else: return JsonResponse({'error': '仅支持POST请求'}, status=405)
关键说明
- 原子更新:
F表达式让数据库直接执行like_votes +=1,避免多用户同时点赞时的数据不一致问题。 - 数据一致性:页面点赞数完全依赖后端返回的最新值,确保前端显示与数据库状态同步。
- CSRF安全:必须添加
csrfmiddlewaretoken参数,通过Django的CSRF验证,避免请求被拦截。
内容的提问来源于stack exchange,提问作者Shaswat
相关产品推荐
相关产品推荐

