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

Discord.py开发:将已删除分类下的频道迁移至新克隆分类问题求助

问题根源

当on_guild_channel_delete事件触发时,你拿到的channel对象对应的分类已经被Discord正式删除,服务器内原属于该分类的频道要么被同步删除,要么已经被移出该分类、解除了和原分类的关联,所以此时调用channel.channels必然返回空列表,这个是Discord API的限制,并非代码逻辑错误。

可行解决方法

你需要提前缓存服务器内每个分类对应的下属频道ID列表,缓存可以用字典结构实时维护,具体实现步骤如下:

  • 机器人启动时,遍历所有服务器的所有频道,初始化缓存:以分类ID为键,对应下属频道ID列表为值
  • 监听on_guild_channel_create、on_guild_channel_update事件,每当频道的所属分类变动时更新缓存
  • 监听on_guild_channel_delete事件时,如果删除的是分类,直接从缓存里拿对应下属频道ID列表,再去服务器里找对应的频道对象,修改所属分类到新克隆的分类即可

示例代码

# 初始化缓存,结构为 {分类ID: [子频道ID1, 子频道ID2, ...]}
category_channel_cache = {}

# 机器人启动时初始化缓存
@bot.event
async def on_ready():
    for guild in bot.guilds:
        for category in guild.categories:
            category_channel_cache[category.id] = [c.id for c in category.channels]
    print("缓存初始化完成")

# 频道更新时维护缓存
@bot.event
async def on_guild_channel_update(before, after):
    # 处理所属分类变更的情况
    if before.category != after.category:
        # 从旧分类缓存移除
        if before.category:
            if before.category.id in category_channel_cache and before.id in category_channel_cache[before.category.id]:
                category_channel_cache[before.category.id].remove(before.id)
        # 加入新分类缓存
        if after.category:
            if after.category.id not in category_channel_cache:
                category_channel_cache[after.category.id] = []
            category_channel_cache[after.category.id].append(after.id)

# 频道创建时维护缓存
@bot.event
async def on_guild_channel_create(channel):
    if channel.category:
        if channel.category.id not in category_channel_cache:
            category_channel_cache[channel.category.id] = []
        category_channel_cache[channel.category.id].append(channel.id)

# 修改原有事件逻辑
@commands.Cog.listener() 
async def on_guild_channel_delete(self, channel):
    # 只处理删除的是分类的情况
    if not isinstance(channel, discord.CategoryChannel):
        return
    try:
        logs = await channel.guild.audit_logs(limit=1, action=discord.AuditLogAction.channel_delete).flatten()
        logs = logs[0]
        if logs.user != channel.guild.owner and logs.user.id != 891409650287796295:
            new_category = await channel.clone(reason="Anti Nuke Protection")
            # 从缓存拿子频道ID列表
            if channel.id in category_channel_cache:
                for channel_id in category_channel_cache[channel.id]:
                    child_channel = channel.guild.get_channel(channel_id)
                    if child_channel:
                        try:
                            await child_channel.edit(category=new_category)
                        except Exception as e:
                            print(f"移动频道失败: {e}")
            # 清理已删除分类的缓存
            del category_channel_cache[channel.id]
    except Exception as e:
        print(f"事件处理出错: {e}")

注:如果用户删除分类时选择了「同时删除所有子频道」,则缓存中拿到的频道ID对应对象已不存在,属于正常业务场景无需额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:06:02