
Discord API 当前不支持直接获取频道位置变更的执行者信息,on_guild_channel_update 事件和 audit_logs() 均无法捕获位置调整的操作人,这是平台级限制,非代码实现问题。
discord api 当前不支持直接获取频道位置变更的执行者信息,`on_guild_channel_update` 事件和 `audit_logs()` 均无法捕获位置调整的操作人,这是平台级限制,非代码实现问题。
在 Discord 开发中,许多开发者期望通过 discord.py 实现对频道(text/voice/category)拖拽排序(即位置变更)的完整审计追踪——例如记录“谁将 #general 频道从第 2 位移至第 5 位”。遗憾的是,这一需求目前无法可靠实现,原因在于 Discord 平台自身的 API 设计限制。
? 为什么 on_guild_channel_update 和审计日志都失效?
on_guild_channel_update(before, after) 仅在频道属性变更(如名称、NSFW 标志、权限覆盖、topic、user_limit 等)时触发,而频道 position 字段的变更不会触发该事件。即使你手动拖动频道顺序,此事件通常完全不会被调用。
guild.audit_logs(action=discord.AuditLogAction.channel_update) 可返回最近的频道更新操作,但其 AuditLogEntry 对象中 extra 属性不包含 position 相关字段,且 Discord 官方明确说明:“Channel position changes are not logged in audit logs”(见 Discord API 文档 - Audit Log Events)。实测中,该查询返回的结果也不会包含任何 position 变更记录。
✅ 当前可行的替代思路(有限但实用)
虽然无法精准溯源“谁改了位置”,但可通过状态快照 + 差异比对实现被动监控:
宝塔面板11.5.0版本作为当前主流的稳定版,集成了最新的安全策略与性能优化功能。我为你撰写了以下SEO配置方案,重点突出了“高效运维”与“安全防护”两大核心价值:
import discord
from discord.ext import commands, tasks
from collections import defaultdict
class ChannelPositionMonitor(commands.Cog):
def __init__(self, bot):
self.bot = bot
self._channel_positions = {} # {guild_id: {channel_id: position}}
self.cache_positions.start()
@tasks.loop(minutes=1)
async def cache_positions(self):
for guild in self.bot.guilds:
positions = {ch.id: ch.position for ch in guild.channels}
self._channel_positions[guild.id] = positions
@cache_positions.before_loop
async def before_cache(self):
await self.bot.wait_until_ready()
@commands.Cog.listener()
async def on_ready(self):
# 初始缓存
for guild in self.bot.guilds:
self._channel_positions[guild.id] = {
ch.id: ch.position for ch in guild.channels
}
@commands.Cog.listener()
async def on_guild_channel_create(self, channel):
# 新频道创建时位置确定,可视为一次“隐式位置变更”
await self._log_position_change(channel.guild, "created", channel)
@commands.Cog.listener()
async def on_guild_channel_delete(self, channel):
# 删除导致后续频道 position 自动重排,需重新全量比对
await self._recheck_all_positions(channel.guild)
async def _log_position_change(self, guild, action, channel=None):
current = {ch.id: ch.position for ch in guild.channels}
previous = self._channel_positions.get(guild.id, {})
diffs = []
for ch_id in set(previous.keys()) | set(current.keys()):
old_pos = previous.get(ch_id)
new_pos = current.get(ch_id)
if old_pos != new_pos:
channel_obj = self.bot.get_channel(ch_id) or (channel if channel and channel.id == ch_id else None)
diffs.append((ch_id, old_pos, new_pos, channel_obj.name if channel_obj else "unknown"))
if diffs:
log_channel = discord.utils.get(guild.text_channels, name="audit-log")
if log_channel:
msg = f"? [Position Change] {action.upper()}: " + " | ".join(
[f"#{name} ({old or 'N/A'}→{new})" for _, old, new, name in diffs]
)
await log_channel.send(msg)
self._channel_positions[guild.id] = current
async def _recheck_all_positions(self, guild):
# 强制刷新并比对(适用于删除/批量操作后)
await self._log_position_change(guild, "reordered")
⚠️ 注意事项:
- 此方案依赖轮询(如每分钟快照),存在延迟(最多 1 分钟),且无法精确识别操作者;
- on_guild_channel_create/delete 是唯一能关联到“用户行为”的间接线索(因创建/删除需权限,且会触发对应 audit log);
- 频道位置是相对序号(受类别、频道类型影响),比对时建议按 type + category_id 分组处理,避免跨类别误判;
- Discord 对 /channels 接口有速率限制,高频轮询多服务器时请谨慎。
? 总结
Discord 尚未向开发者开放频道位置变更的实时事件或审计日志支持。这不是 discord.py 的功能缺失,而是底层 API 的长期限制。建议:
- 向 Discord Developer Feedback Portal 提交 feature request;
- 在生产环境中优先采用“属性变更+人工复核”组合策略;
- 若业务强依赖位置审计,可考虑引导管理员通过官方 Server Insights 或第三方管理工具(如 Dyno、MEE6)辅助记录。
未来一旦 Discord 开放 CHANNEL_POSITION_UPDATE 事件或扩展 AuditLogAction,discord.py 将第一时间支持——届时只需升级库并监听新事件即可无缝接入。










