如何实现基于数据库条目的Slash Command动态Options?
为Discord Slash Command添加基于数据库条目动态变化的选项
需求描述
要给sell命令添加动态选项:用户执行命令时,仅显示其数据库中数量不为空的股票符号作为可选值。例如用户userx的数据库中IMPJ和IMGR的值为“1”和“748”,其余条目为None,执行sell命令时就只显示这两个选项。
尝试的错误代码
@stocks.command(name="sell", description="Sell your stocks") cursor.execute("SELECT bank, IMAW, IMBG, IMGR, IMPJ, MACB, MAY FROM economy WHERE user_id = %s", (user_id,)) user_data = cursor.fetchone() choices = [] if user_data: bank_balance, imaw_quantity, imbg_quantity, imgr_quantity, impj_quantity, macb_quantity, may_quantity = user_data quantities = [imaw_quantity, imbg_quantity, imgr_quantity, impj_quantity, macb_quantity, may_quantity] items = ["IMAW", "IMBG", "IMGR", "IMPJ", "MACB", "MAY"] for quantity, item in zip(quantities, items): if quantity: choices.append(item) print(choices) @option("symbol", description="Choose what stock you want to sell", choices=choices)
错误信息
File "/GIS_Main/Cogs/economy.py", line 890 cursor.execute("SELECT bank, IMAW, IMBG, IMGR, IMPJ, MACB, MAY FROM economy WHERE user_id = %s", (user_id,)) ^ SyntaxError: invalid syntax
错误原因:Python不允许在@x.command()装饰器和命令的async def定义之间直接插入执行代码,装饰器仅用于修饰函数/方法,中间不能放置可执行语句。
解决方案:用自动补全(Autocomplete)实现动态选项
Slash Command的静态choices参数无法在运行时根据用户数据动态更新,必须使用Autocomplete功能来实现需求,具体步骤如下:
1. 编写Autocomplete回调函数
该函数会在用户触发命令时被调用,查询当前用户的数据库数据,返回可用的股票选项:
async def stock_autocomplete(interaction: discord.Interaction, current: str) -> list[app_commands.Choice[str]]: # 查询当前用户的股票数据 cursor.execute("SELECT IMAW, IMBG, IMGR, IMPJ, MACB, MAY FROM economy WHERE user_id = %s", (interaction.user.id,)) user_data = cursor.fetchone() choices = [] if user_data: quantities = list(user_data) items = ["IMAW", "IMBG", "IMGR", "IMPJ", "MACB", "MAY"] # 筛选数量不为空且匹配用户输入的股票 for quantity, item in zip(quantities, items): if quantity and item.lower().startswith(current.lower()): choices.append(app_commands.Choice(name=item, value=item)) # 最多返回25个选项(Discord的限制) return choices[:25]
2. 修改Sell命令定义
在@option装饰器中指定autocomplete参数为上述回调函数,替换原来的静态choices:
@stocks.command(name="sell", description="Sell your stocks") @app_commands.describe(symbol="Choose what stock you want to sell") @app_commands.autocomplete(symbol=stock_autocomplete) async def sell(interaction: discord.Interaction, symbol: str): # 这里编写命令的核心逻辑,比如处理股票出售操作 await interaction.response.send_message(f"你选择出售的股票是:{symbol}")
关键注意事项
- Autocomplete回调函数必须是异步的,需接收
interaction(用于获取当前用户ID)和current(用户当前输入的内容,用于过滤选项)两个参数。 - 必须返回
app_commands.Choice对象列表,每个对象包含name(显示给用户的文本)和value(传递给命令函数的实际值)。 - 若使用同步数据库驱动,建议用
asyncio.to_thread包裹数据库操作,避免阻塞事件循环:
# 在autocomplete函数中修改数据库查询部分 await asyncio.to_thread( cursor.execute, "SELECT IMAW, IMBG, IMGR, IMPJ, MACB, MAY FROM economy WHERE user_id = %s", (interaction.user.id,) ) user_data = await asyncio.to_thread(cursor.fetchone)
内容的提问来源于stack exchange,提问作者Karo
相关产品推荐
相关产品推荐

