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

discord.py warn命令无法发送embed及相关报错与mongodb问题求解

问题描述

我正在尝试使用discord.py开发警告(warn)命令,采用MongoDB作为数据库存储处罚记录、以及日志embed需要发送的频道配置。当前代码如下:

@commands.command()
@commands.has_permissions(manage_messages=True)
async def warn(self, ctx, member: discord.Member, *, reason=None):
    ctx.logging = cluster["Logging"]["Punishments logs"]
    self.channel = cluster["Logging"]["logchannels"]
    embed = discord.Embed(title="\u200b", color=0x008000)
    warn_embed = discord.Embed(
        colour=discord.Color.magenta()
        )
    warn_embed.set_author(name='Punishment Notifcation')
    warn_embed.add_field(name=f'You have been warned in **{ctx.guild.name}**', value=f'For `{reason}.`', inline=True)
    if member == ctx.author:
        await ctx.channel.send("You can't warn yourself :person_facepalming:")
        return
    elif reason == None:
        reason = "No stated reason"
        await member.send(embed=warn_embed)
        await ctx.send(f'{member.mention} has been warned.')
        print(f'{ctx.author} warned {member.mention} for {reason}')
        ctx.logging.insert_one({"guild_id": ctx.guild.id, "action": "warn", "moderator": ctx.author.id, "user": member.id, "reason": reason})
        channel = self.setup.find_one({"guild_id": ctx.guild.id})
        if channel is not None:
            elif_embed = discord.Embed(
                title=f'Warn | Case (case number in future)',
                color=discord.Color.magenta()
                )
            elif_embed.set_author(name=member, url=discord.Embed.Empty, icon_url=member.avatar_url)
            elif_embed.add_field(name=f'**Offender:**', value=f'{member} {member.mention}')
            elif_embed.add_field(name=f'**Reason:**', value=f'{reason}')
            elif_embed.add_field(name='**Responsible Moderator:**', value=f'{ctx.author} {ctx.author.mention}')
            await ctx.send(embed=elif_embed)
        else:
            await ctx.send('This command cannot be logged as moderation logs have not been enabled. To enable them do: **+setupmod <channel>**')

    else:
        await member.send(embed=warn_embed)
        await ctx.send(f'{member.mention} has been warned by {ctx.author.mention}')
        print(f'{ctx.author} warned {member} for {reason}')
        ctx.logging.insert_one({"guild_id": ctx.guild.id, "action": "warn", "moderator": ctx.author.id, "user": member.id, "reason": reason})
        channel = self.setup.find_one({"guild_id": ctx.guild.id})
        if channel is not None:
            else_embed = discord.Embed(
                title=f'Warn | Case (case number in future)',
                color=discord.Color.magenta()
                )
            else_embed.set_author(name=member, url=discord.Embed.Empty, icon_url=member.avatar_url)
            else_embed.add_field(name=f'**Offender:**', value=f'{member} {member.mention}')
            else_embed.add_field(name=f'**Reason:**', value=f'`{reason}`')
            else_embed.add_field(name='**Responsible Moderator:**', value=f'{ctx.author} {ctx.author.mention}')
            await ctx.send(embed=else_embed)
        else:
            await ctx.send('This command cannot be logged as moderation logs have not been enabled. To enable them do: **+setupmod <channel>**')

预期效果

  • 在命令执行的频道发送操作成功的确认消息
  • 向被警告用户发送私信告知其被警告
  • 若已配置日志频道,则向该频道发送日志embed

实际运行结果

前两项功能正常运行,但embed无法发送到已设置的对应频道,同时触发以下报错:

Ignoring exception in on_message
Traceback (most recent call last):
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "c:\Users\name\Documents\Discord Bot\Testcode.py", line 98, in on_message
    guild = setup.find_one({"guild_id": message.guild.id})
AttributeError: 'NoneType' object has no attribute 'id'


Discord Username #1234 warned <@!759497745886085132> for No stated reason
Ignoring exception in on_command_error
Traceback (most recent call last):
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "c:\Users\name\Documents\Discord Bot\cogs\moderation.py", line 100, in warn
    channel = self.setup.find_one({"guild_id": ctx.guild.id})
AttributeError: 'Moderation' object has no attribute 'setup'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "c:\Users\name\Documents\Discord Bot\Testcode.py", line 231, in on_command_error
    raise error
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "C:\Users\name\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Moderation' object has no attribute 'setup'

我已经尝试用print命令排查错误没有结果,在Discord支持服务器求助也未得到解决,查阅过往可运行代码及discord.py官方文档也没找到解决方法,需要相关解决方案。
另外如果您了解MongoDB,也麻烦提供为每条处罚记录分配ID的实现思路,谢谢。

补充说明

报错第一部分指向的代码片段如下:

@bot.event
async def on_message(message):
    setup = cluster["Atomic_Developer_Bot"]["prefix"]
    guild = setup.find_one({"guild_id": message.guild.id})
    prefix = guild["prefix"]
    if message.content.startswith('<@850794452364951554>'):
        await message.channel.send(f'The current prefix is **{prefix}**')
    else:
        print(prefix)
    await bot.process_commands(message)
解决方案

1. 修复AttributeError: 'Moderation' object has no attribute 'setup'报错

错误原因是你在Moderation cog类中没有定义setup实例属性,但代码中调用了self.setup.find_one()。你在warn函数开头已经定义了存储日志频道配置的集合self.channel = cluster["Logging"]["logchannels"],直接把所有self.setup.find_one替换为self.channel.find_one即可。
另外注意你当前查到频道配置后,是调用ctx.send往命令执行频道发embed,不是往配置的日志频道发,需要修改为:

# 查到配置后先获取频道对象,cog内用self.bot获取bot实例
log_channel = self.bot.get_channel(channel["channel_id"])
if log_channel: # 加判断避免频道被删报错
    await log_channel.send(embed=elif_embed) # 或者else_embed

额外优化提醒:你当前的warn_embed创建在reason赋值之前,当用户未填写reason时,用户收到的私信里reason会显示为None.,建议把warn_embed的创建逻辑放到reason赋值完成之后,避免这个问题。

2. 修复AttributeError: 'NoneType' object has no attribute 'id'报错

错误出现在on_message事件中,原因是私信场景下message.guild为None,访问id属性就会报错。同时需要增加服务器未配置前缀时的默认值判断,避免查询结果为空时报错。修改后的代码如下:

@bot.event
async def on_message(message):
    # 非服务器消息直接跳过前缀处理
    if not message.guild:
        await bot.process_commands(message)
        return
    setup = cluster["Atomic_Developer_Bot"]["prefix"]
    guild = setup.find_one({"guild_id": message.guild.id})
    # 没有配置前缀时使用默认前缀,替换为你自己的默认前缀即可
    prefix = guild["prefix"] if guild else "+"
    if message.content.startswith('<@850794452364951554>'):
        await message.channel.send(f'The current prefix is **{prefix}**')
    else:
        print(prefix)
    await bot.process_commands(message)

MongoDB处罚记录分配ID实现思路

MongoDB插入文档时会自动生成唯一的_id字段作为主键,如果你需要可读性更高的自增数字案件ID,可以通过单独的计数器集合实现:

  1. 新建counters集合存储各业务的当前最大ID,初始化一条处罚ID计数记录:
{"_id": "punishment_id", "sequence_value": 0}
  1. 编写获取下一个可用ID的函数:
def get_next_case_id():
    result = cluster["Logging"]["counters"].find_one_and_update(
        {"_id": "punishment_id"},
        {"$inc": {"sequence_value": 1}},
        return_document=True
    )
    return result["sequence_value"]
  1. 插入处罚记录时新增case_id字段即可:
case_id = get_next_case_id()
ctx.logging.insert_one({
    "case_id": case_id,
    "guild_id": ctx.guild.id, 
    "action": "warn", 
    "moderator": ctx.author.id, 
    "user": member.id, 
    "reason": reason
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:54:02