pytelegrambotapi开发Telegram机器人:如何存储用户输入实现待编辑ID复用?
跨消息处理函数的状态共享方案
Telebot 每个通过装饰器注册的消息处理函数都是独立作用域,无法直接读取其他函数内的临时变量,需要通过全局隔离的存储位置保存用户之前输入的待编辑ID,适配你当前的轻量开发场景,最适合用按用户chat.id隔离的全局状态字典实现:
- 存储逻辑基于Telegram用户chat.id唯一的特性,不同用户的编辑状态完全隔离,不会出现A用户的ID被B用户读到的问题
- 状态结构简单直接,不需要引入额外的数据库、缓存组件
首先在代码全局位置定义状态存储容器:
# 全局用户编辑状态字典 # 结构:{chat_id: {"current_edit_id": 待编辑的行号, "current_edit_field": 当前选中的修改字段}} user_edit_state = {}
改造原有的ID输入处理函数,拿到用户输入的行号后直接存入状态字典:
def get_list_options(message): # 先校验用户输入的合法性,避免非数字输入报错 try: target_row_id = int(message.text) except ValueError: bot.send_message(message.chat.id, "请输入合法的数字行ID") return # 将待编辑ID绑定到当前用户的状态下 user_edit_state[message.chat.id] = { "current_edit_id": target_row_id } bot.send_message(message.chat.id, str(get_all_options(target_row_id))) bot.send_message(message.chat.id, "现在可以直接发送/字段名(如/Price、/Shop)选择要修改的参数")
编写通用的字段选择处理函数,直接从状态字典读取之前存的待编辑ID,不需要跨函数硬取变量:
@bot.message_handler(commands=['Name', 'Price', 'Shop']) def handle_field_select(message): current_chat_id = message.chat.id # 前置校验:用户是否已经选择了待编辑的行ID if current_chat_id not in user_edit_state or "current_edit_id" not in user_edit_state[current_chat_id]: bot.send_message(current_chat_id, "请先通过/options_list选择要编辑的记录行号") return # 取出用户选中的字段名(去掉消息开头的斜杠) selected_field = message.text.strip('/') # 将选中的字段存入状态 user_edit_state[current_chat_id]["current_edit_field"] = selected_field bot.send_message(current_chat_id, f"请输入新的{selected_field}值") # 注册下一步处理流程,等待用户输入新值 bot.register_next_step_handler(message, handle_new_value) def handle_new_value(message): current_chat_id = message.chat.id current_state = user_edit_state.get(current_chat_id, {}) # 校验状态完整性,避免状态失效导致的报错 if not current_state.get("current_edit_id") or not current_state.get("current_edit_field"): bot.send_message(current_chat_id, "编辑状态失效,请重新从/options_list开始操作") return # 读取状态中存储的ID、字段,结合用户刚输入的新值,执行数据库更新 update_product( row_id=current_state["current_edit_id"], field=current_state["current_edit_field"], new_value=message.text ) bot.send_message(current_chat_id, "修改完成。你可以继续发送/字段名修改同一条记录的其他参数,或重新选择其他行ID")
现有代码的安全修正
你当前使用字符串拼接生成SQL的写法存在两个核心问题:
- 存在SQL注入风险,用户输入的恶意字符串会直接拼进SQL语句执行
- 拼接时没有给字符串值加引号,碰到文本类字段会直接报语法错误
修正后的数据库更新函数示例:
# 预先定义允许修改的字段白名单,避免字段名被篡改 ALLOWED_FIELDS = ["name", "price", "shop"] def update_product(row_id, field, new_value): # 校验字段合法性 if field not in ALLOWED_FIELDS: print("Error: 非法修改字段") return try: # 使用参数化查询,将值作为参数传入,不直接拼入SQL语句 cur.execute( f"UPDATE products SET {field} = ? WHERE id = ?", (new_value, row_id) ) conn.commit() print("OK") except Exception as e: conn.rollback() print(f"Error! 执行原因:{e}")
原有自定义命令的优化
你之前为/milk、/banana等字段单独写重复处理函数的逻辑可以完全删掉,通用的字段处理函数已经覆盖了所有修改场景——只要状态里存了当前待编辑的行ID,用户输入任何已注册的字段命令,都可以直接完成修改,不需要重复编写取ID、传参、发消息的重复代码。
内容的提问来源于stack exchange,提问作者Goncharoff
相关产品推荐
相关产品推荐

