Flask+MySQL插入正常但无法更新数据问题求助
问题原因分析
你的更新逻辑犯了一个典型的SQLAlchemy使用错误:当你编辑现有记录时,你创建了一个全新的Location实例,但这个实例并没有和SQLAlchemy会话中的已有数据库记录关联起来。SQLAlchemy只会对两种对象执行持久化操作:
- 新创建并通过
db.session.add()加入会话的对象(对应插入操作) - 从数据库查询出来、之后被修改属性的对象(对应更新操作)
你直接新建的Location对象虽然带有正确的loc_id,但它只是内存中的独立对象,SQLAlchemy无法识别它对应数据库里的哪条记录,所以执行db.session.commit()时不会生成任何UPDATE语句。
修复方案
有两种简洁的修复方式,任选其一即可:
方案1:查询现有记录并修改属性(推荐)
这是SQLAlchemy更新记录的标准做法,先从数据库获取目标对象,修改其属性后提交会话:
修改routes.py中POST处理的代码块,替换掉新建Location对象的部分:
if request.method == "POST" and form.validate_on_submit(): try: if loc_id == "0": # 插入逻辑保持不变 location = Location(loc_id=form.loc_id.data, \ loc_name=form.loc_name.data, \ loc_detail=form.loc_detail.data, \ loc_postal_code=form.loc_postal_code.data ) db.session.add(location) loc_str = location.loc_name + ', ' + location.loc_detail if location.loc_detail else location.loc_name flash('Location (' + loc_str + ') added.', 'success') else: # 更新逻辑:先查询已有记录,再修改属性 location = Location.query.get(form.loc_id.data) if not location: flash('Location not found!', 'error') return redirect(url_for('location')) # 更新属性 location.loc_name = form.loc_name.data location.loc_detail = form.loc_detail.data location.loc_postal_code = form.loc_postal_code.data loc_str = location.loc_name + ', ' + location.loc_detail if location.loc_detail else location.loc_name flash('Location (' + loc_str + ') updated.', 'success') db.session.commit() return redirect(url_for('location')) # 异常处理部分保持不变 except IntegrityError: logging.error("edit_location(): Intg Exception occurred", exc_info=True) db.session.rollback() flash('Location (' + loc_str + ') already exists.', 'error') except DatabaseError: logging.error("edit_location(): DB Exception occurred", exc_info=True) db.session.rollback() except Exception as e: flash('Error in form, site administrators have been notified. We apologize for the inconvenience.', 'error') logging.error("edit_location(): Exception occurred", exc_info=True)
方案2:使用db.session.merge()合并对象
如果你更倾向于通过新建对象来更新,可以使用merge()方法让SQLAlchemy把新对象和数据库中的已有记录关联起来:
if request.method == "POST" and form.validate_on_submit(): try: location = Location(loc_id=form.loc_id.data, \ loc_name=form.loc_name.data, \ loc_detail=form.loc_detail.data, \ loc_postal_code=form.loc_postal_code.data ) logging.info("edit_location(): location:" + str(location.loc_postal_code)) loc_str = location.loc_name + ', ' + location.loc_detail if location.loc_detail else location.loc_name if loc_id == "0": db.session.add(location) flash('Location (' + loc_str + ') added.', 'success') else: # 关键:用merge将新对象与会话中的记录关联 db.session.merge(location) flash('Location (' + loc_str + ') updated.', 'success') db.session.commit() return redirect(url_for('location')) # 异常处理部分保持不变 except IntegrityError: logging.error("edit_location(): Intg Exception occurred", exc_info=True) db.session.rollback() flash('Location (' + loc_str + ') already exists.', 'error') except DatabaseError: logging.error("edit_location(): DB Exception occurred", exc_info=True) db.session.rollback() except Exception as e: flash('Error in form, site administrators have been notified. We apologize for the inconvenience.', 'error') logging.error("edit_location(): Exception occurred", exc_info=True)
额外提示
- 方案1是更推荐的做法,因为它能明确保证你操作的是数据库中最新的记录,避免并发更新导致的数据覆盖问题。
- 你可以在更新逻辑里加一个
if not location的判断,处理记录被删除的极端情况,提升代码健壮性。
内容的提问来源于stack exchange,提问作者Cmdr Nudnik
相关产品推荐
相关产品推荐

