Flask SQLAlchemy多对多关联无法插入重复用户餐食记录问题求助
问题原因
你遇到的问题是SQLAlchemy多对多关系的默认行为和你的业务需求不匹配导致的,既不是关联配置错误也不是基础代码逻辑错误,是选型用错了:
- 普通多对多关系的设计目的是维护两个模型的唯一关联集合,比如用户收藏的菜单、用户拥有的角色,同一个用户和同一个菜单的关联只会存在1条
- 你执行
menu.menu_user.append(user)的时候,SQLAlchemy会自动检测到该关联已经存在,不会生成新的插入SQL,所以第二次提交没有报错也不会插入数据,你哪怕给中间表的id_resep和id_user设了unique=False也没用,这是多对多关系的内置去重逻辑
解决方案
你的业务需要记录用户每次的进食行为,允许同一个用户多次食用同一道菜,所以不能用普通多对多关系,要把中间表改成关联模型:
第一步:修改中间表定义
把原来的db.Table类型的中间表改成继承db.Model的实体模型:
# 替换原来的menu_hidangan_user表定义 class MenuHidanganUser(db.Model): __tablename__ = 'menu_hidangan_user' id = db.Column(db.Integer, primary_key=True) id_resep = db.Column(db.Integer, db.ForeignKey('resep.id'), nullable=False) id_user = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) timestamp = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp()) # 可选配置:方便后续关联查询 resep = db.relationship('Resep', backref='konsumsi_records') user = db.relationship('Users', backref='konsumsi_records')
第二步:调整关联配置(可选)
可以把原来Users模型里的menu_makanan多对多关系删掉,如果你需要保留用来查询用户吃过的所有不重复菜单,可以加viewonly=True参数避免误用:
menu_makanan = db.relationship( 'Resep', secondary=menu_hidangan_user, backref="menu_user", viewonly=True)
第三步:修改接口插入逻辑
不要用append方法添加关联,直接实例化关联模型插入即可:
@app.route(f'{ENDPOINT}/hidangan', methods=['POST']) def addHidangan(): try: id_menu = request.json['id_menu'] id_user = request.json['id_user'] # 校验用户和菜单合法性 menu = Resep.query.filter_by(id=id_menu).first() user = Users.query.filter_by(id=id_user).first() if not menu or not user: return jsonify({'statusCode': 400, 'err': True, 'message': '用户或菜单不存在'}), 400 # 直接新建进食记录,允许重复 new_record = MenuHidanganUser(id_resep=id_menu, id_user=id_user) db.session.add(new_record) db.session.commit() return jsonify({'statusCode': 200, 'message': 'Success'}) except Exception as e: db.session.rollback() return jsonify({'statusCode': 400, 'err': True, 'message': str(e)}), 400
修改后重新生成表结构,重复提交相同的用户ID和菜单ID就会生成多条记录了。
内容的提问来源于stack exchange,提问作者Insight Habor
相关产品推荐
相关产品推荐

