discord.py报错:'Button'对象无'response'属性及房间选择需求
Discord房间预订机器人问题修复与功能实现
问题描述
我正在开发一款连接Discord与Google Sheets的房间预订机器人,执行!reserver指令会弹出一个按钮,但点击按钮时触发交互错误,报错信息为:AttributeError: 'Button' object has no attribute 'response'。同时希望实现点击按钮后显示房间选择菜单的功能。
源代码
import discord from discord.ext import commands from discord.ui import Button, View, Select import gspread from oauth2client.service_account import ServiceAccountCredentials import logging logging.basicConfig(level=logging.ERROR) intents = discord.Intents.default() intents.message_content = True intents.members = True bot = commands.Bot(command_prefix='!', intents=intents) def get_gspread_client(): scope = [ "https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive" ] creds = ServiceAccountCredentials.from_json_keyfile_name( "reservation-salles-brique-901c122a60ee.json", scope) return gspread.authorize(creds) def get_room_names(): client = get_gspread_client() spreadsheet = client.open('Réservation des salles') worksheet = spreadsheet.worksheet('Nom des salles') room_names = [ item['Nom de la salle'] for item in worksheet.get_all_records() ] return room_names class RoomSelect(Select): def __init__(self): room_names = get_room_names() options = [discord.SelectOption(label=room) for room in room_names] super().__init__(placeholder='Sélectionnez une salle...', options=options) async def callback(self, interaction: discord.Interaction): self.view.room = self.values[0] self.view.stop() class TimeInputView(View): def __init__(self): super().__init__() self.room = None @discord.ui.button(label="Réserver", style=discord.ButtonStyle.green) async def reserve_button(self, button: discord.ui.Button, interaction: discord.Interaction): try: if self.room: # ... await interaction.response.send( f'Réservation confirmée pour {self.room} dans la feuille "Réservation".' ) else: await interaction.response.send('Veuillez sélectionner une salle.') except gspread.exceptions.APIError as e: logging.error(f"Erreur lors de l'interaction avec Google Sheets : {e}") except discord.errors.DiscordException as e: logging.error(f"Erreur lors de l'interaction avec Discord : {e}") @bot.command() async def reserver(ctx): view = TimeInputView() await ctx.send( "Veuillez sélectionner la salle que vous souhaitez réserver :", view=view) @bot.event async def on_ready(): print(f'Bot connecté comme {bot.user}') bot.run('TOKEN')
错误日志
ERROR discord.ui.view Ignoring exception in view <TimeInputView timeout=180.0 children=1> for item <Button style=<ButtonStyle.success: 3> url=None disabled=False label='Réserver' emoji=None row=None> Traceback (most recent call last): File "/home/runner/Bot-reservation-discord/.pythonlibs/lib/python3.10/site-packages/discord/ui/view.py", line 427, in _scheduled_task await item.callback(interaction) File "/home/runner/Bot-reservation-discord/main.py", line 67, in reserve_button await interaction.response.send('Veuillez sélectionner une salle.') AttributeError: 'Button' object has no attribute 'response' ERROR:discord.ui.view:Ignoring exception in view <TimeInputView timeout=180.0 children=1> for item <Button style=<ButtonStyle.success: 3> url=None disabled=False label='Réserver' emoji=None row=None> Traceback (most recent call last): File "/home/runner/Bot-reservation-discord/.pythonlibs/lib/python3.10/site-packages/discord/ui/view.py", line 427, in _scheduled_task await item.callback(interaction) File "/home/runner/Bot-reservation-discord/main.py", line 67, in reserve_button await interaction.response.send('Veuillez sélectionner une salle.') AttributeError: 'Button' object has no attribute 'response'
修复与功能实现方案
核心问题解析
- 交互响应方法错误:Discord.py中
interaction.response没有send方法,正确的发送交互响应方法是send_message,这是导致AttributeError的直接原因。 - 流程逻辑缺失:原代码中用户没有途径选择房间,点击按钮时
self.room始终为None,不符合“点击按钮显示房间选择菜单”的需求。
修改后的完整代码
import discord from discord.ext import commands from discord.ui import Button, View, Select import gspread from oauth2client.service_account import ServiceAccountCredentials import logging logging.basicConfig(level=logging.ERROR) intents = discord.Intents.default() intents.message_content = True intents.members = True bot = commands.Bot(command_prefix='!', intents=intents) def get_gspread_client(): scope = [ "https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive" ] creds = ServiceAccountCredentials.from_json_keyfile_name( "reservation-salles-brique-901c122a60ee.json", scope) return gspread.authorize(creds) def get_room_names(): client = get_gspread_client() spreadsheet = client.open('Réservation des salles') worksheet = spreadsheet.worksheet('Nom des salles') room_names = [ item['Nom de la salle'] for item in worksheet.get_all_records() ] return room_names class RoomSelect(Select): def __init__(self): room_names = get_room_names() options = [discord.SelectOption(label=room) for room in room_names] super().__init__(placeholder='Sélectionnez une salle...', options=options) async def callback(self, interaction: discord.Interaction): selected_room = self.values[0] # 此处可添加写入Google Sheets的逻辑 await interaction.response.send_message( f'Réservation confirmée pour la salle : {selected_room}.' ) self.view.stop() class ReservationView(View): def __init__(self): super().__init__() @discord.ui.button(label="Réserver", style=discord.ButtonStyle.green) async def reserve_button(self, button: discord.ui.Button, interaction: discord.Interaction): try: # 创建包含房间选择菜单的View select_view = View() select_view.add_item(RoomSelect()) # 发送带选择菜单的交互响应 await interaction.response.send_message( "Veuillez sélectionner la salle que vous souhaitez réserver :", view=select_view ) except gspread.exceptions.APIError as e: logging.error(f"Erreur lors de l'interaction avec Google Sheets : {e}") except discord.errors.DiscordException as e: logging.error(f"Erreur lors de l'interaction avec Discord : {e}") @bot.command() async def reserver(ctx): view = ReservationView() await ctx.send( "Cliquez sur le bouton pour commencer la réservation :", view=view) @bot.event async def on_ready(): print(f'Bot connecté comme {bot.user}') bot.run('TOKEN')
关键改动说明
- 修正交互响应方法:将
interaction.response.send()替换为interaction.response.send_message(),符合Discord.py的API规范。 - 重构View逻辑:点击“Réserver”按钮时,动态生成包含房间选择菜单的View并发送,实现“点击按钮显示房间选择菜单”的需求。
- 优化选择回调:在
RoomSelect的回调中直接处理房间选择结果,可在此处扩展写入Google Sheets的业务逻辑。
内容的提问来源于stack exchange,提问作者Allan Scharff
相关产品推荐
相关产品推荐

