FastAPI中@event.listens_for('after_delete')不生效,无法删除缓存求助
问题原因及解决方案
为什么after_delete事件没触发?
SQLAlchemy的@event.listens_for监听的是ORM实例对象的删除动作,而你在delete_item里用的是delete()构造SQL级别的删除语句,这种方式直接向数据库发送删除指令,不会创建或加载对应的ORM实例,自然不会触发实例相关的after_delete事件。
两种解决办法
方法1:修改DAO删除逻辑,触发ORM事件
把delete_item里的SQL级删除改成删除ORM实例,这样就能触发after_delete事件:
async def delete_item(self, item_id: int) -> bool: item = await self.get_item_by_id(item_id) if not item: return False try: # 替换成删除ORM实例的方式 await self.session.delete(item) await self.session.flush() except SQLAlchemyError as exc: logger.error(exc.args) raise return True
这样修改后,after_delete监听器会正常触发,无需改动其他逻辑。
方法2:不修改DAO核心逻辑,手动清理缓存
如果不想改动DAO的删除逻辑(避免影响其他路由),可以在删除成功后,通过已获取的ORM实例拿到language_id,手动调用缓存清理:
# 修改DAO的delete_item,返回删除状态和对应的language_id async def delete_item(self, item_id: int) -> tuple[bool, int | None]: item = await self.get_item_by_id(item_id) if not item: return False, None language_id = item.language_id try: await self.session.execute(delete(self.model).where(self.model.id == item_id)) await self.session.flush() except SQLAlchemyError as exc: logger.error(exc.args) raise return True, language_id # 路由里处理缓存清理 @router.delete("/{id}", status_code=status.HTTP_200_OK) async def delete_translate(id: int, session: AsyncSession = Depends(get_db)): async with TranslateDao(session) as dao: success, language_id = await dao.delete_item(id) if success and language_id: cache.clear(f'delete_translate-{language_id}') return success
这种方式既保留了原DAO的SQL级删除逻辑,又能拿到language_id清理缓存,不会破坏其他路由的调用(其他路由仅需接收返回的布尔值即可,元组的第二个值不会被使用)。
额外注意事项
- 确保
@event.listens_for装饰的监听器代码被正确导入到应用启动的模块中,否则监听器不会被注册。 - 异步环境下的SQLAlchemy事件监听器必须用
async定义,你的代码已经满足这一点。
内容的提问来源于stack exchange,提问作者Сергей Севастьянов
相关产品推荐
相关产品推荐

