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

如何在discord.py重启后重新连接含按钮的考勤视图?

解决discord.py重启后恢复按钮视图的方案

要实现bot重启后恢复带按钮的考勤视图,核心是利用discord.py的**持久化视图(Persistent Views)**功能,再配合消息与状态的持久化存储,具体步骤如下:

1. 配置持久化视图

给视图和按钮设置固定的custom_id,并将视图的timeout设为None(永久生效),让Discord服务器记住按钮的交互绑定:

class AttendanceView(discord.ui.View):
    def __init__(self):
        # timeout设为None,视图永久有效
        super().__init__(timeout=None)

    # 给按钮设置唯一固定的custom_id
    @discord.ui.button(label="签到", custom_id="attendance_checkin", style=discord.ButtonStyle.success)
    async def checkin_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
        # 你的签到逻辑,比如记录用户ID到存储中
        await interaction.response.send_message("签到成功!", ephemeral=True)

    @discord.ui.button(label="签退", custom_id="attendance_checkout", style=discord.ButtonStyle.danger)
    async def checkout_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
        # 你的签退逻辑
        await interaction.response.send_message("签退成功!", ephemeral=True)

2. 启动时注册持久化视图

在on_ready事件中注册视图,避免多次触发事件时重复注册:

@bot.event
async def on_ready():
    # 用自定义属性标记注册状态,防止重复注册
    if not hasattr(bot, "attendance_view_registered"):
        bot.add_view(AttendanceView())
        bot.attendance_view_registered = True
        print("考勤持久化视图已注册")

3. 持久化消息与考勤状态

把考勤消息的ID、频道ID,以及已签到用户的数据存储起来(推荐用JSON、SQLite),重启后可通过这些数据找回消息并恢复视图。

示例:发送考勤消息时存储数据

import json
import os

ATTENDANCE_DATA_PATH = "attendance_data.json"

async def send_attendance_panel(channel_id: int):
    channel = bot.get_channel(channel_id)
    if not channel:
        print("指定频道不存在")
        return
    
    view = AttendanceView()
    message = await channel.send("📅 考勤签到/签退面板", view=view)
    
    # 初始化存储数据
    data = {
        "message_id": message.id,
        "channel_id": channel_id,
        "checked_in_users": []
    }
    
    with open(ATTENDANCE_DATA_PATH, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2)
    
    print("考勤面板已发送并存储数据")

示例:签到时更新存储数据

在签到按钮逻辑中同步更新存储的用户列表:

# 替换AttendanceView中的checkin_btn方法
async def checkin_btn(self, interaction: discord.Interaction, button: discord.ui.Button):
    user_id = str(interaction.user.id)
    # 读取现有数据
    with open(ATTENDANCE_DATA_PATH, "r", encoding="utf-8") as f:
        data = json.load(f)
    
    if user_id not in data["checked_in_users"]:
        data["checked_in_users"].append(user_id)
        # 写回更新后的数据
        with open(ATTENDANCE_DATA_PATH, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2)
        await interaction.response.send_message("签到成功!", ephemeral=True)
    else:
        await interaction.response.send_message("你已经签到过了", ephemeral=True)

4. 重启bot后恢复视图

在on_ready事件中读取存储的数据,找到对应消息并重新绑定视图:

@bot.event
async def on_ready():
    if not hasattr(bot, "attendance_view_registered"):
        bot.add_view(AttendanceView())
        bot.attendance_view_registered = True
        print("考勤持久化视图已注册")
        
        # 尝试恢复考勤面板视图
        if os.path.exists(ATTENDANCE_DATA_PATH):
            with open(ATTENDANCE_DATA_PATH, "r", encoding="utf-8") as f:
                data = json.load(f)
            
            try:
                channel = bot.get_channel(data["channel_id"])
                message = await channel.fetch_message(data["message_id"])
                # 重新绑定视图
                await message.edit(view=AttendanceView())
                print("考勤面板视图已成功恢复")
            except discord.NotFound:
                print("存储的考勤消息不存在,无法恢复视图")
            except Exception as e:
                print(f"恢复视图失败:{str(e)}")

关键注意事项

  • custom_id必须固定且唯一,不能动态生成,否则Discord无法关联之前的按钮交互。
  • 存储介质推荐用SQLite/MySQL代替JSON,避免文件损坏或并发写入问题。
  • 如果有多个考勤面板,需要存储每条消息的信息并遍历恢复。
  • 若bot重启后找不到目标消息(如已被删除),可自动重新发送新面板并同步之前的考勤数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:52:35