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

Flask项目中取消点赞后仍显示已点赞的问题修复求助

Flask点赞功能异常修复:取消点赞后状态不更新

问题现象

用户取消点赞后,点赞按钮颜色仍显示为已点赞状态,点赞数也未减少。各状态表现:

  • 未点赞时:未点赞状态
  • 已点赞时:已点赞状态
  • 取消点赞后异常状态:取消点赞后异常

问题代码分析

后端路由代码

@app.route('/postlikes/<string:post_name>', methods=["GET","POST"])
def postlikes(post_name):
    if request.method == "POST":
        JSONdata = request.json
        posts = Image.query.filter_by(post_name=post_name)
        if JSONdata['is_liked'] == True:
            for post in posts:
                post.likes += 1
                db.session.commit()
        elif JSONdata['removed_like'] == True:
            for post in posts:
                post.likes = post.likes  # 错误:未减少点赞数
                db.session.commit()
    else:
        post = Image.query.filter_by(post_name=post_name).first()
        return {"post_likes":post.likes}
            
@app.route('/hasliked/<string:post_name>', methods=['GET','POST'])
def hasliked(post_name):
    post = Image.query.filter_by(post_name=post_name).first()
    user = User.query.filter_by(username=current_user.username).first()
    is_liked = posts_liked_by_users.query.filter_by(post_name=post_name).first()
    if is_liked.post_name == post.post_name and is_liked.user_id == user.id:  # 错误:无数据时会抛异常
        return {"has_liked":True}
    else:
        return {"has_liked":False}

前端JS代码

<script>
    const likebtn = document.getElementById('likebtn');
    const currentURL = window.location.href;
    const likenum = document.getElementById('likenumber');
    const postarray = currentURL.split("/");
    const postName = postarray[4];

    function setLikeBtnColor() {
        likebtn.style.color = JSON.parse(localStorage.getItem('likebtn')) ? 'cornflowerblue':'black';
    }

    setLikeBtnColor();

    async function current_color() {
        const fetchData = await fetch('/hasliked/'+postName)
        .then(response => response.json())
        .then(function newdata(data) {
            let strdata = JSON.stringify(data)
            let JSONdata = JSON.parse(strdata)  // 冗余:无需重复序列化反序列化
            return JSONdata
        })
        return fetchData
    }

    async function set_color() {
        const jsondata = await current_color()
        if (jsondata['has_liked'] === true) {
            likebtn.style.color = 'cornflowerblue'
        } else {
            likebtn.style.color = 'black'
        }
    }

    async function getLikeNumber() {
        const fetchData = await fetch('/postlikes/'+postName)
        .then(response => response.json())
        .then(function getdata(data) {
            let strdata = JSON.stringify(data)
            let JSONdata = JSON.parse(strdata)  // 冗余:无需重复序列化反序列化
            likenum.textContent = JSONdata.post_likes
            return JSONdata.post_likes
        })
        return fetchData
    }

    async function displayLikes() {
        let initialnum = await getLikeNumber()
        likenum.innerHTML = initialnum
    }
    displayLikes()

    async function myFunction() {
        localStorage.setItem('likebtn', !JSON.parse(localStorage.getItem('likebtn')));
        setLikeBtnColor();
        // 错误:先改UI再发请求,请求失败会导致状态不一致
        if (likebtn.style.color === 'cornflowerblue') {
            fetch('/postlikes/'+postName, {
                method:"POST",
                body: JSON.stringify({
                    removed_like: false,
                    liked_post:postName,
                    is_liked:true
                }),
                headers:{
                    "Content-type":"application/json; charset=UTF-8"
                }
            })
            let currentLikeNum = await getLikeNumber();
            likenum.innerHTML = currentLikeNum
        } else {
            fetch('/postlikes/'+postName, {
                method:"POST",
                body: JSON.stringify({
                    removed_like:true,
                    is_liked:false
                }),
                headers:{
                    "Content-type":"application/json; charset=UTF-8"
                }
            })
            let currentLikeNum = await getLikeNumber();
            likenum.innerHTML = currentLikeNum
        }};
    likebtn.addEventListener('click', myFunction);
</script>

Image数据表定义

class Image(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title=db.Column(db.String(120), nullable=False)
    date_posted = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
    img_location = db.Column(db.String(600), nullable=False)
    mimetype = db.Column(db.String(10))
    post_name = db.Column(db.String(150),nullable=False, unique=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    manga_name = db.Column(db.String(100), unique=False, nullable=False)
    likes = db.Column(db.Integer, nullable=False)
    reports = db.Column(db.Integer, nullable=False)
    number_of_comments = db.Column(db.Integer, nullable=False)

修复方案

1. 修复后端点赞计数与状态判断逻辑

修改postlikes路由中取消点赞的代码,同时完善hasliked路由的查询逻辑,避免无数据时抛异常,还要同步维护用户点赞关系表:

@app.route('/postlikes/<string:post_name>', methods=["GET","POST"])
def postlikes(post_name):
    if request.method == "POST":
        JSONdata = request.json
        posts = Image.query.filter_by(post_name=post_name)
        user = current_user
        if not user.is_authenticated:
            return {"status": "error", "msg": "未登录"}
        
        if JSONdata.get('is_liked'):
            # 增加点赞数
            for post in posts:
                post.likes += 1
            # 同步记录用户点赞关系
            existing_like = posts_liked_by_users.query.filter_by(
                post_name=post_name, user_id=user.id
            ).first()
            if not existing_like:
                new_like = posts_liked_by_users(post_name=post_name, user_id=user.id)
                db.session.add(new_like)
            db.session.commit()
        elif JSONdata.get('removed_like'):
            # 减少点赞数(避免负数)
            for post in posts:
                if post.likes > 0:
                    post.likes -= 1
            # 删除用户点赞关系
            existing_like = posts_liked_by_users.query.filter_by(
                post_name=post_name, user_id=user.id
            ).first()
            if existing_like:
                db.session.delete(existing_like)
            db.session.commit()
    else:
        post = Image.query.filter_by(post_name=post_name).first()
        return {"post_likes": post.likes if post else 0}
            
@app.route('/hasliked/<string:post_name>', methods=['GET','POST'])
def hasliked(post_name):
    if not current_user.is_authenticated:
        return {"has_liked": False}
    # 同时按post_name和用户ID查询,准确判断当前用户是否点赞
    is_liked = posts_liked_by_users.query.filter_by(
        post_name=post_name,
        user_id=current_user.id
    ).first()
    return {"has_liked": is_liked is not None}

2. 修复前端状态同步逻辑

去掉冗余的JSON序列化操作,优先依赖后端状态更新UI,避免先改UI再发请求导致的不一致:

<script>
    const likebtn = document.getElementById('likebtn');
    const currentURL = window.location.href;
    const likenum = document.getElementById('likenumber');
    const postarray = currentURL.split("/");
    const postName = postarray[4];

    // 从后端获取并设置按钮状态
    async function setLikeBtnState() {
        try {
            const response = await fetch('/hasliked/' + postName);
            const data = await response.json();
            likebtn.style.color = data.has_liked ? 'cornflowerblue' : 'black';
            // 可选:用localStorage缓存状态,用于离线场景
            localStorage.setItem(`likebtn_${postName}`, data.has_liked);
        } catch (err) {
            console.error('获取点赞状态失败:', err);
            // 离线时用localStorage缓存的状态
            const cachedState = JSON.parse(localStorage.getItem(`likebtn_${postName}`)) || false;
            likebtn.style.color = cachedState ? 'cornflowerblue' : 'black';
        }
    }

    // 获取并更新点赞数
    async function updateLikeNumber() {
        try {
            const response = await fetch('/postlikes/' + postName);
            const data = await response.json();
            likenum.textContent = data.post_likes;
        } catch (err) {
            console.error('获取点赞数失败:', err);
        }
    }

    // 初始化页面状态
    async function initPageState() {
        await Promise.all([setLikeBtnState(), updateLikeNumber()]);
    }
    initPageState();

    // 处理点赞按钮点击事件
    async function handleLikeClick() {
        try {
            // 先获取当前后端状态
            const stateRes = await fetch('/hasliked/' + postName);
            const currentState = await stateRes.json();
            const newState = !currentState.has_liked;

            // 发送修改请求
            await fetch('/postlikes/' + postName, {
                method: "POST",
                body: JSON.stringify({
                    is_liked: newState,
                    removed_like: !newState
                }),
                headers: {
                    "Content-type": "application/json; charset=UTF-8"
                }
            });

            // 请求成功后更新UI和缓存
            likebtn.style.color = newState ? 'cornflowerblue' : 'black';
            localStorage.setItem(`likebtn_${postName}`, newState);
            await updateLikeNumber();
        } catch (err) {
            console.error('点赞操作失败:', err);
            // 请求失败时刷新状态,回滚UI
            await initPageState();
        }
    }

    likebtn.addEventListener('click', handleLikeClick);
</script>

3. 关键注意点

  • 必须确保posts_liked_by_users表在点赞/取消点赞时同步新增/删除记录,否则hasliked接口无法正确判断用户点赞状态
  • 增加用户登录校验,避免未登录用户操作点赞
  • 点赞数修改时增加边界判断,防止出现负数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:15:44