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

discord.py实现分页排行榜 每页限制展示10位用户

discord.py 排行榜分页改造方案

核心改造逻辑

原实现存在两个明显问题:一是全量加载所有用户数据到单条Embed,很容易触碰Discord单Embed 6000字符的上限导致发送失败;二是用list.index()循环查找排名的时间复杂度过高,用户量过百就会出现明显卡顿。
改造直接按以下思路落地:

  1. 把排序后的资产数据转成列表结构,用enumerate直接生成排名,去掉低效的索引查找逻辑
  2. 按每页10条对排序后的列表做切片,拆分出所有分页数据
  3. 用discord.py原生的View组件实现翻页按钮,自动处理页码边界、超时禁用逻辑

改造后完整代码

首先在文件顶部补充需要的依赖导入:

import math
import json
import discord
from discord.ext import commands

指令部分实现代码:

@commands.command()
@commands.guild_only()
@commands.cooldown(1, 3, commands.BucketType.guild)
async def leaderboard(self, ctx):
    # 读取服务器用户数据
    with open(f'json/servers/{ctx.guild.id}/User.json', 'r') as f:
        users = json.load(f)

    # 计算用户总资产并生成有序列表,避免后续反复遍历查索引
    total_amt = []
    for user_id, user_data in users.items():
        total_assets = user_data['MONEY'] + user_data['BANK']
        total_amt.append((user_id, total_assets))
    # 按资产从高到低排序
    leaderboard = sorted(total_amt, key=lambda item: item[1], reverse=True)
    
    # 分页参数配置
    per_page = 10
    total_pages = math.ceil(len(leaderboard) / per_page)
    current_page = 0

    # 按页码生成对应Embed的工具方法
    async def gen_page_embed(page_num: int) -> discord.Embed:
        page_slice = leaderboard[page_num*per_page : (page_num+1)*per_page]
        em = discord.Embed(title='Top de Dinero', color=0x96edfd)
        rank_content = []
        # 直接用enumerate生成全局排名,不需要反复查列表索引
        for global_rank, (user_id, assets) in enumerate(page_slice, start=page_num*per_page + 1):
            user_obj = self.bot.get_user(int(user_id))
            user_show = user_obj.mention if user_obj else 'None'
            rank_content.append(f'**{global_rank}.** {user_show} **{assets}**')
        em.description = '\n'.join(rank_content)
        em.set_footer(text=f'第 {page_num+1}/{total_pages} 页')
        return em

    # 翻页交互视图
    class LeaderboardView(discord.ui.View):
        def __init__(self, timeout=60):
            super().__init__(timeout=timeout)
            self.page = 0

        async def refresh_page(self, interaction: discord.Interaction):
            # 自动处理按钮禁用状态:第一页禁用上一页,最后一页禁用下一页
            self.children[0].disabled = self.page <= 0
            self.children[1].disabled = self.page >= total_pages - 1
            new_embed = await gen_page_embed(self.page)
            await interaction.response.edit_message(embed=new_embed, view=self)

        @discord.ui.button(label='上一页', style=discord.ButtonStyle.primary, disabled=True)
        async def prev(self, interaction: discord.Interaction, button: discord.ui.Button):
            self.page -= 1
            await self.refresh_page(interaction)

        @discord.ui.button(label='下一页', style=discord.ButtonStyle.primary)
        async def next(self, interaction: discord.Interaction, button: discord.ui.Button):
            self.page += 1
            await self.refresh_page(interaction)

        # 交互超时后自动禁用所有按钮,避免无效点击
        async def on_timeout(self):
            for child in self.children:
                child.disabled = True
            await self.message.edit(view=self)

    # 发送首页内容
    init_embed = await gen_page_embed(current_page)
    view = LeaderboardView()
    # 总数据不足10条时直接禁用下一页
    if total_pages <= 1:
        view.children[1].disabled = True
    view.message = await ctx.send(embed=init_embed, view=view)

注意事项

  • 上述实现基于discord.py 2.0+版本,如果你使用1.x旧版本,把按钮交互换成wait_for监听消息反应即可,核心的分页切片逻辑完全通用
  • 单服务器用户量超过1000时,建议把JSON存储换成SQLite等轻量数据库,减少文件读写和全量排序的耗时
  • 翻页交互默认超时时间为60秒,可根据需求自行调整View初始化时的timeout参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:12:27