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

Discord.py中给Modal添加discord.ui.Select报错及替代方案咨询

解决Discord Modal中无法使用Select组件的问题

错误原因

报错信息Value of field "type" must be one of (4,)明确说明:Discord的Modal组件仅支持类型为4的组件(即TextInput文本输入框),API层面不允许在Modal中添加Select下拉选择器,这是核心限制,所以添加Select后会触发400 Bad Request错误。

替代方案(适配View场景)

因为你使用的是View而非斜杠命令,无法直接用Literal参数,以下是三个可行的替代思路:


方案1:用单选按钮组替代Select

先展示包含分类选项的按钮View,用户选择后再弹出仅含TextInput的Modal收集工单原因。

示例代码:

class TicketCategoryView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=90)
        self.selected_category = None

    @discord.ui.button(label="Become an admin", emoji="👮", style=discord.ButtonStyle.primary)
    async def admin_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
        self.selected_category = "Become an admin"
        self.stop()
        await interaction.response.send_modal(TicketReasonModal(self.selected_category))

    @discord.ui.button(label="A script problem", emoji="📜", style=discord.ButtonStyle.primary)
    async def script_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
        self.selected_category = "A script problem"
        self.stop()
        await interaction.response.send_modal(TicketReasonModal(self.selected_category))

    @discord.ui.button(label="Other ...", emoji="🤔", style=discord.ButtonStyle.primary)
    async def other_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
        self.selected_category = "Other ..."
        self.stop()
        await interaction.response.send_modal(TicketReasonModal(self.selected_category))

class TicketReasonModal(discord.ui.Modal):
    def __init__(self, category):
        super().__init__(title="Ticket", timeout=90)
        self.category = category
        self.add_item(discord.ui.TextInput(label="Raison", placeholder="Raison du ticket",
                      custom_id="reason_input", max_length=50, min_length=10))

    async def on_submit(self, interaction: discord.Interaction):
        reason = self.children[0].value
        embed = discord.Embed(title=f"Ticket created!", color=discord.Color.blurple())
        embed.add_field(name="**Salon**", value=f"{ticket_channel_mention}", inline=True)
        embed.add_field(name="**Category**", value=f"{self.category}", inline=True)
        embed.add_field(name="**Raison**", value=f"{reason}", inline=True)
        embed.set_thumbnail(url=icon_url)
        await interaction.response.send_message(embed=embed, ephemeral=True)

方案2:用TextInput配合关键词验证

在Modal中添加两个TextInput,第一个要求用户输入指定分类关键词(如admin/script/other),提交时验证输入合法性,不符合则提示重新输入。

示例代码:

class TicketInputReason(discord.ui.Modal):
    def __init__(self):
        super().__init__(title="Ticket", timeout=90)
        self.add_item(discord.ui.TextInput(label="Catégorie du ticket", placeholder="输入 admin/script/other 选择分类",
                      custom_id="category_input", max_length=10, min_length=4))
        self.add_item(discord.ui.TextInput(label="Raison", placeholder="Raison du ticket",
                      custom_id="reason_input", max_length=50, min_length=10))

    async def on_submit(self, interaction: discord.Interaction):
        category_input = self.children[0].value.lower()
        category_map = {
            "admin": "Become an admin 👮",
            "script": "A script problem 📜",
            "other": "Other ... 🤔"
        }
        if category_input not in category_map:
            await interaction.response.send_message("请输入正确的分类关键词:admin/script/other", ephemeral=True)
            return
        category = category_map[category_input]
        reason = self.children[1].value
        embed = discord.Embed(title=f"Ticket created!", color=discord.Color.blurple())
        embed.add_field(name="**Salon**", value=f"{ticket_channel_mention}", inline=True)
        embed.add_field(name="**Category**", value=f"{category}", inline=True)
        embed.add_field(name="**Raison**", value=f"{reason}", inline=True)
        embed.set_thumbnail(url=icon_url)
        await interaction.response.send_message(embed=embed, ephemeral=True)

方案3:先显示Select菜单View,再弹出Modal

保留原有的Select组件逻辑,但将其放在独立的View中,用户选择分类后再触发原因收集的Modal。

示例代码:

class TicketCategorySelect(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=90)
        options = [
            discord.SelectOption(label="Become an admin", emoji="👮"),
            discord.SelectOption(label="A script problem", value="script", emoji="📜"),
            discord.SelectOption(label="Other ...", value="Other", emoji="🤔")
        ]
        self.add_item(discord.ui.Select(
            placeholder="Catégorie du ticket", options=options, custom_id="category_select", min_values=1, max_values=1))

    async def on_select(self, interaction: discord.Interaction, select: discord.ui.Select):
        selected_category = select.values[0]
        self.stop()
        await interaction.response.send_modal(TicketReasonModal(selected_category))

class TicketReasonModal(discord.ui.Modal):
    def __init__(self, category):
        super().__init__(title="Ticket", timeout=90)
        self.category = category
        self.add_item(discord.ui.TextInput(label="Raison", placeholder="Raison du ticket",
                      custom_id="reason_input", max_length=50, min_length=10))

    async def on_submit(self, interaction: discord.Interaction):
        reason = self.children[0].value
        embed = discord.Embed(title=f"Ticket created!", color=discord.Color.blurple())
        embed.add_field(name="**Salon**", value=f"{ticket_channel_mention}", inline=True)
        embed.add_field(name="**Category**", value=f"{self.category}", inline=True)
        embed.add_field(name="**Raison**", value=f"{reason}", inline=True)
        embed.set_thumbnail(url=icon_url)
        await interaction.response.send_message(embed=embed, ephemeral=True)

内容的提问来源于stack exchange,提问作者Le Rat Gondin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 19:45:29