Python Flask实现点赞点踩功能时SQLAlchemy外键关联报错如何解决
报错修复方案
原因:你的Post模型存在user_id、recipient_id两个字段同时关联User表主键,SQLAlchemy无法自动判定User.posts关系对应的外键路径,需要手动指定foreign_keys参数。
修改方法:调整User模型中的posts关系配置,明确关联的外键,同时可补充接收帖子的反向关系(按需选择):
# User模型修改部分 class User(db.Model): # 原有字段保留不变 # 修改posts关系,指定关联Post.user_id,backref重命名为author避免和接收人混淆 posts = db.relationship("Post", foreign_keys='Post.user_id', backref="author", lazy=True) # 可选:新增接收帖子的反向关系,关联Post.recipient_id received_posts = db.relationship("Post", foreign_keys='Post.recipient_id', backref="recipient", lazy=True) # 其余原有关系、方法保留不变
修改后重启服务即可解决该报错。
完整点赞+点踩功能实现
1. 调整数据模型
1.1 修改PostLike表,新增操作类型标识
class PostLike(db.Model): __tablename__ = 'post_like' id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False) # 新增字段:1=点赞,-1=点踩 operate_type = db.Column(db.Integer, nullable=False) # 联合唯一约束,避免同一用户对同一帖子重复添加记录 __table_args__ = ( db.UniqueConstraint('user_id', 'post_id', name='_user_post_uc'), )
1.2 Post表新增统计字段(可选,提升查询性能)
不用每次请求都统计点赞点踩数量,直接读取字段即可
class Post(db.Model): # 原有字段保留不变 like_count = db.Column(db.Integer, default=0, comment='点赞数') dislike_count = db.Column(db.Integer, default=0, comment='点踩数')
1.3 扩充User模型的操作方法
自动处理互斥逻辑,不能同时点赞和点踩
class User(db.Model): # 原有字段、关系保留不变 def operate_post(self, post, operate_type): # 先清除用户对该帖子的原有操作 old_operate = PostLike.query.filter_by(user_id=self.id, post_id=post.id).first() if old_operate: if old_operate.operate_type == 1: post.like_count -= 1 else: post.dislike_count -= 1 db.session.delete(old_operate) # 新增当前操作 new_operate = PostLike(user_id=self.id, post_id=post.id, operate_type=operate_type) if operate_type == 1: post.like_count += 1 else: post.dislike_count += 1 db.session.add(new_operate) def cancel_operate(self, post): # 取消用户对该帖子的操作 operate = PostLike.query.filter_by(user_id=self.id, post_id=post.id).first() if operate: if operate.operate_type == 1: post.like_count -= 1 else: post.dislike_count -= 1 db.session.delete(operate) def has_liked_post(self, post): return PostLike.query.filter( PostLike.user_id == self.id, PostLike.post_id == post.id, PostLike.operate_type == 1 ).count() > 0 def has_disliked_post(self, post): return PostLike.query.filter( PostLike.user_id == self.id, PostLike.post_id == post.id, PostLike.operate_type == -1 ).count() > 0
2. 调整路由逻辑
新增登录校验、操作类型校验,避免非法请求
from flask import redirect, request, session, abort @app.route('/operate_post/<int:post_id>/<action>') def operate_post(post_id, action): # 登录校验 if 'user_id' not in session: # 可自定义跳转到登录页或返回401错误 abort(401) # 从数据库查询当前用户对象 current_user = User.query.get(session['user_id']) if not current_user: abort(401) post = Post.query.filter_by(id=post_id).first_or_404() if action == 'like': current_user.operate_post(post, 1) db.session.commit() elif action == 'dislike': current_user.operate_post(post, -1) db.session.commit() elif action == 'cancel': current_user.cancel_operate(post) db.session.commit() else: # 非法操作类型返回400 abort(400) return redirect(request.referrer)
3. 前端适配建议
- 渲染帖子时,通过
current_user.has_liked_post(post)和current_user.has_disliked_post(post)判断用户当前操作状态,给对应按钮添加激活样式 - 按钮点击请求对应路由即可,后端已做幂等处理,无需额外判断重复操作
内容的提问来源于stack exchange,提问作者DatNinjaGarage
相关产品推荐
相关产品推荐

