
本文深入探讨了 `discord.py` 中 `discord.ui.View` 类的 `interaction_check` 方法的正确使用,以解决因过度限制导致部分按钮无法响应的问题。通过分析原始代码的逻辑缺陷,文章提供了一种分按钮定制交互检查的解决方案,确保不同功能按钮(如“确认”和“撤销”)能独立根据其业务逻辑(用户ID匹配或角色权限)进行权限验证,从而提升交互组件的灵活性和用户体验。
在 discord.py 中,discord.ui.View 提供了一种构建交互式组件(如按钮、选择菜单)的方式,使其能够附加到消息上。View 类中的 interaction_check 方法是一个强大的工具,用于在任何组件的交互回调被触发之前,对交互进行全局性的预检查。如果 interaction_check 返回 False,则相应的组件回调将不会执行,并且可以向用户发送一条错误消息。
其基本作用是为视图中的所有组件定义一个通用的权限或条件。然而,不当的 interaction_check 逻辑可能导致某些按钮的功能被意外阻止,即使这些按钮在其自身的逻辑中包含了正确的权限检查。
考虑以下场景:一个 View 包含“确认 (Acknowledge)”和“撤销 (Revoke)”两个按钮。
原始的 interaction_check 实现如下:
async def interaction_check(self, interaction: discord.Interaction) -> bool:
    userid = int(self.user_id)
    if interaction.user.id == userid and interaction.data["custom_id"] == "acknowledge":
        return True
    else:
        await interaction.response.send_message("你无权使用此按钮。", ephemeral=True)
        return False此代码段的逻辑是:只有当交互用户ID与 self.user_id 匹配,并且 被点击的按钮 custom_id 为 "acknowledge" 时,才允许交互继续。否则,无论点击哪个按钮,都会发送一条错误消息并阻止交互。
问题分析: 当用户点击“撤销”按钮时,interaction.data["custom_id"] 将是 "revoke"。此时,interaction.user.id == userid and interaction.data["custom_id"] == "acknowledge" 这个条件将评估为 False(因为 interaction.data["custom_id"] 不等于 "acknowledge")。因此,interaction_check 会立即返回 False,阻止“撤销”按钮的回调函数执行,即使“撤销”按钮内部有自己的角色检查逻辑。这就是导致“撤销”按钮无法工作的根本原因。
为了解决这个问题,我们需要优化 interaction_check 的逻辑,使其能够区分不同的按钮,并应用相应的检查,或者在某些情况下允许交互通过,以便按钮自身的逻辑能够处理权限。
核心思想是:
以下是修改后的 MyView 类和 interaction_check 方法:
import discord
from discord import Embed, app_commands
from discord.app_commands import Choice
class MyView(discord.ui.View):
    def __init__(self, user_id: str):
        super().__init__(timeout=None) # Consider adding a timeout
        self.user_id = user_id
    async def interaction_check(self, interaction: discord.Interaction) -> bool:
        """
        根据按钮的 custom_id 进行条件检查,以允许不同按钮执行其特定的权限逻辑。
        """
        button_custom_id = interaction.data.get("custom_id")
        # 对于 "acknowledge" 按钮,执行用户ID匹配检查
        if button_custom_id == "acknowledge":
            if interaction.user.id == int(self.user_id):
                return True
            else:
                await interaction.response.send_message("你无权确认此消息。", ephemeral=True)
                return False
        # 对于 "revoke" 按钮,允许其通过 interaction_check,
        # 具体的角色权限检查将在其自身的异步回调函数中完成。
        elif button_custom_id == "revoke":
            return True 
        # 对于其他未明确处理的按钮,默认拒绝交互
        else:
            await interaction.response.send_message("你无权使用此按钮。", ephemeral=True)
            return False
    @discord.ui.button(label="Acknowledge", emoji="<:check:1135773225423491122>", style=discord.ButtonStyle.grey, custom_id="acknowledge")
    async def menu1(self, interaction: discord.Interaction, button: discord.ui.Button):
        # 这里的 interaction_check 已经确保只有授权用户才能点击此按钮
        new_embed = Embed.from_dict(interaction.message.embeds[0].to_dict())
        new_embed.set_footer(text=f'Sent by {interaction.user.name}     |     Acknowledged: ✔')
        await interaction.response.edit_message(embed=new_embed)
        button.disabled = True
        await interaction.message.edit(view=self)
    @discord.ui.button(label="Revoke", emoji="<:Cross:1135773287880867900>", style=discord.ButtonStyle.grey, custom_id="revoke")
    async def menu2(self, interaction: discord.Interaction, button: discord.ui.Button):
        # interaction_check 允许此按钮的回调执行,现在在此处进行角色检查
        user = interaction.guild.get_member(interaction.user.id)
        # 建议使用配置或环境变量存储角色ID,而非硬编码
        role_headquarters_id = 994233392478560297
        role_first_line_supervisors_id = 994233182532685825
        role1 = discord.utils.get(interaction.guild.roles, id=role_headquarters_id)
        role2 = discord.utils.get(interaction.guild.roles, id=role_first_line_supervisors_id)
        # 确保角色存在,避免NoneType错误
        if role1 and role2 and (role1 in user.roles or role2 in user.roles):
            await interaction.response.send_message(f"**惩罚已由 {interaction.user.mention} 撤销**", ephemeral=False)
            await interaction.message.delete()
        else:
            await interaction.response.send_message("你没有所需的角色来使用此按钮。", ephemeral=True)
# 你的机器人命令部分 (保持不变)
# @bot.tree.command(name="infract")
# ... (省略,与问题内容相同)代码解释:
以上就是优化 Discord.py 视图中的交互检查逻辑的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号