You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JavaScript通过PUT方法实现数据库点赞数自增

问题根因

代码失效来自三个明确的问题:

  • 异步执行时序错误:fetch是异步非阻塞API,你写的PUT请求不会等GET请求拿到返回结果就会直接执行,此时声明的postLikes还未被赋值,值为undefined,执行自增操作后结果就是NaN。
  • 变量名拼写错误:你声明的变量名为驼峰格式postLikes(L大写),但GET请求的回调里赋值时写的是全小写开头的postlikes(l小写),两个是完全独立的变量,就算时序正确也无法完成赋值。
  • 逻辑存在并发缺陷:就算修正前两个问题,「前端先GET获取旧值→加1→PUT更新」的逻辑在多用户同时点赞时会出现计数丢失,两个用户同时拿到相同的旧点赞数,最终只会成功加1次。
修正步骤

1. 修复前端JS逻辑

把PUT请求放到GET请求的Promise回调链中,保证拿到帖子数据后再执行更新,同时修正变量名,补上Django要求的CSRF请求头:

function likePost(postID) {
  fetch(`/posts/${postID}`)
    .then(response => {
      if (!response.ok) throw new Error('帖子不存在')
      return response.json()
    })
    .then(post => {
      return fetch(`/posts/${postID}`, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRFToken': getCookie('csrftoken')
        },
        body: JSON.stringify({
          liked: true
        })
      })
    })
    .then(response => response.json())
    .then(updatedPost => {
      // 此处更新页面上的点赞数展示即可
      console.log('点赞成功,当前点赞数:', updatedPost.likes)
    })
    .catch(err => console.error('点赞操作失败:', err))
}

// Django官方提供的CSRF令牌读取工具函数
function getCookie(name) {
  let cookieValue = null;
  if (document.cookie && document.cookie !== '') {
    const cookies = document.cookie.split(';');
    for (let i = 0; i < cookies.length; i++) {
      const cookie = cookies[i].trim();
      if (cookie.substring(0, name.length + 1) === (name + '=')) {
        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
        break;
      }
    }
  }
  return cookieValue;
}

这里前端PUT请求不需要传likes字段,点赞数的计算完全放到后端处理,从根源避免前端传值导致的计数错误。

2. 优化后端更新逻辑(解决并发计数问题)

修改views.py中对应路由的PUT处理逻辑,用Django内置的F()表达式做数据库层面的原子更新,不需要依赖前端传入的点赞数值:

from django.db.models import F
from django.http import JsonResponse
from .models import Post
import json

def post(request, post_id):
    try:
        target_post = Post.objects.get(pk=post_id)
    except Post.DoesNotExist:
        return JsonResponse({"error": "Post not found"}, status=404)
    
    if request.method == "GET":
        return JsonResponse(target_post.serialize())
    
    if request.method == "PUT":
        req_data = json.loads(request.body)
        # 数据库层面原子执行点赞数+1,避免并发场景下计数丢失
        target_post.likes = F('likes') + 1
        target_post.liked = req_data.get("liked", False)
        target_post.save()
        # 刷新对象拿到更新后的实际值
        target_post.refresh_from_db()
        return JsonResponse(target_post.serialize())

3. 修复模型层小缺陷

你定义的Post模型中likes字段没有设置默认值,创建新帖子时如果不手动传值会触发数据库报错,建议修改为:

likes = models.IntegerField(default=0)

内容的提问来源于stack exchange,提问作者Daniel Garcia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:57:20