You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py重启部署后角色选择器与按钮失效问题求助

问题描述

我编写了一段discord.py代码,用于生成带角色选择器的Embed,用户可通过选择器获取对应角色。代码原本运行正常,但重新部署Bot后,所有按钮与角色选择器均失效,求解决方法(重点针对选择器)。

代码示例

@bot.command(name="add-role-pick")
async def add_role_pick(ctx: commands.Context, max_value_select: int):
    embed_title = 'Тестовый заголовок'

    ### >>> view

    view = discord.ui.View(timeout=None)

    add_role_button = discord.ui.Button(label="Добавить роль", style=discord.ButtonStyle.primary)
    edit_title_button = discord.ui.Button(label="Изменить название", style=discord.ButtonStyle.secondary)
    edit_description_button = discord.ui.Button(label="Изменить описание", style=discord.ButtonStyle.secondary)
    send_button = discord.ui.Button(label="Отправить", style=discord.ButtonStyle.green)
    edit_image_button = discord.ui.Button(label="Добавить картинку", style=discord.ButtonStyle.secondary)

    async def select_callback(interaction: discord.Interaction):
        user = interaction.user
        print(select.options)
        for role_id in select.values:
            role = interaction.message.guild.get_role(int(role_id))
            await user.add_roles(role)
        await interaction.response.send_message("Роли выданы", ephemeral=True)

    select = discord.ui.Select(placeholder="Выберите роль", min_values=1, max_values=max_value_select)
    select.callback = select_callback

    async def add_role_button_callback(interaction):
        await interaction.response.send_message("Введите название роли в селекте, затем упомяните роль", ephemeral=True)
        role_answer = await bot.wait_for("message", check=check)
        role_name = role_answer.content[:len(role_answer.content) - 23]
        role_id = role_answer.raw_role_mentions[0]
        await role_answer.delete()
        view.remove_item(select)
        select.add_option(value=role_id, label=role_name)
        if len(select.options) >= 2:
            view.add_item(select)
        await ctx.send('Роль добавлена', ephemeral=True)
        await resend_message()

    add_role_button.callback = add_role_button_callback

    async def send_button_callback(interaction):
        result_view = discord.ui.View(timeout=None)
        result_view.add_item(select)
        await bot.get_channel(981167385140682779).send(embed=result_embed, view=result_view)
        await interaction.response.send_message("Сообщение отправлено!", ephemeral=True)
        await embed_message.delete()

    send_button.callback = send_button_callback

    async def edit_title_button_callback(interaction: discord.Interaction):
        await interaction.response.send_message("Отправьте название Embed в чат", ephemeral=True)
        title_answer = await bot.wait_for("message", check=check)
        result_embed.title = title_answer.content
        await interaction.message.delete()
        await resend_message()

    edit_title_button.callback = edit_title_button_callback

    async def edit_description_button_callback(interaction: discord.Interaction):
        await interaction.response.send_message("Отправьте описание Embed в чат", ephemeral=True)
        description_answer = await bot.wait_for("message", check=check)
        result_embed.description = description_answer.content
        await interaction.message.delete()
        await resend_message()

    edit_description_button.callback = edit_description_button_callback

    async def edit_image_button_callback(interaction: discord.Interaction):
        await interaction.response.send_message("Отправьте ссылку на картинку в чат", ephemeral=True)
        image_answer = await bot.wait_for("message", check=check)
        result_embed.set_image(url=image_answer.content)
        await interaction.message.delete()
        await resend_message()

    edit_image_button.callback = edit_image_button_callback

    view.add_item(add_role_button)
    view.add_item(edit_title_button)
    view.add_item(edit_description_button)
    view.add_item(edit_image_button)
    view.add_item(send_button)

    ### <<< view

    author_id = ctx.message.author.id

    result_embed = discord.Embed(title=embed_title, color=discord.Color.from_rgb(32, 34, 37))

    embed_message = await ctx.send(embed=result_embed, view=view, ephemeral=True)

    async def resend_message():
        await embed_message.edit(embed=result_embed, view=view)

    def check(m):
        return author_id == m.author.id
解决方案

核心原因:持久视图未注册

discord.py中,设置timeout=None的持久化视图必须通过bot.add_view()注册,否则Bot重启后无法识别之前发送的交互组件,这是部署后组件失效的最常见原因。

具体修复步骤:

  1. 注册发送后的角色选择视图
    修改send_button_callback函数,在发送消息前注册result_view:

    async def send_button_callback(interaction):
        result_view = discord.ui.View(timeout=None)
        result_view.add_item(select)
        # 注册视图,确保Bot重启后仍能响应交互
        bot.add_view(result_view)
        await bot.get_channel(981167385140682779).send(embed=result_embed, view=result_view)
        await interaction.response.send_message("Сообщение отправлено!", ephemeral=True)
        await embed_message.delete()
    
  2. 优化选择器动态修改逻辑
    原代码中反复移除/添加选择器的逻辑容易出错,改为直接检查选择器是否已在视图中再添加:

    # 替换add_role_button_callback中的对应代码
    select.add_option(value=role_id, label=role_name)
    # 仅当选择器不在视图中且选项数≥2时添加
    if len(select.options) >= 2 and select not in view.children:
        view.add_item(select)
    await resend_message()
    
  3. 验证Bot权限
    重新部署后确认Bot拥有以下权限:

    • Manage Roles:用于给用户添加角色
    • Send Messages、Embed Links:发送Embed消息
    • Use Application Commands:响应交互组件
  4. 改用类继承视图(推荐)
    动态绑定回调的方式在持久化场景下不稳定,建议用类定义视图,便于维护和注册:

    class RoleSelectView(discord.ui.View):
        def __init__(self, max_values):
            super().__init__(timeout=None)
            self.select = discord.ui.Select(placeholder="Выберите роль", min_values=1, max_values=max_values)
            self.select.callback = self.select_callback
            self.add_item(self.select)
    
        async def select_callback(self, interaction: discord.Interaction):
            user = interaction.user
            for role_id in self.select.values:
                role = interaction.message.guild.get_role(int(role_id))
                await user.add_roles(role)
            await interaction.response.send_message("Роли выданы", ephemeral=True)
    

    然后在发送时实例化并注册:

    async def send_button_callback(interaction):
        result_view = RoleSelectView(max_value_select)
        bot.add_view(result_view)
        await bot.get_channel(981167385140682779).send(embed=result_embed, view=result_view)
        # 其余代码不变
    
  5. 统一discord.py版本
    确保部署环境与本地测试使用的discord.py版本一致,避免版本差异导致的兼容问题,推荐使用稳定版(如discord.py==2.3.2)。


内容的提问来源于stack exchange,提问作者metacore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:35:24