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

discord.py中Button对象无user属性的AttributeError问题求助

问题分析与解决方案

错误原因

你遇到的AttributeError: 'Button' object has no attribute 'user'是因为按钮回调函数的参数顺序错误。在discord.py v2.x中,@discord.ui.button装饰的回调函数,正确的参数顺序是:self → interaction: discord.Interaction → button: discord.ui.Button(可选)。

你的代码中将button放在了interaction前面,导致discord.py调用函数时,把Interaction对象传给了button参数,把Button对象传给了interaction参数。后续代码中你尝试访问interaction.user,但此时的interaction实际是Button对象,自然没有user属性。

修复后的核心代码

修正参数顺序,并补充交互回应、私信权限检查、超时处理等必要优化:

class DepositView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)  # 设置View永久有效,除非手动停止

    @discord.ui.button(label='Пополнить!', custom_id='deposit_button', style=discord.ButtonStyle.primary)
    async def deposit_button_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
        # 先回应交互,避免Discord显示"交互失败"提示
        await interaction.response.send_message('已向你发送私信,请查看', ephemeral=True)

        # 检查用户是否允许接收私信
        try:
            await interaction.user.send('Какую сумму вы хотите пополнить?')
        except discord.Forbidden:
            await interaction.followup.send('无法向你发送私信,请开启私信权限后重试', ephemeral=True)
            return

        # 等待用户回复,设置5分钟超时
        try:
            response = await bot.wait_for(
                'message',
                check=lambda m: m.author == interaction.user and isinstance(m.channel, discord.DMChannel),
                timeout=300
            )
        except asyncio.TimeoutError:
            await interaction.user.send('Время ожидания истекло,请重新发起存款请求')
            return

        try:
            amount = int(response.content)
            if amount <= 0:
                await interaction.user.send('Пожалуйста, введите положительное число')
                return

            total_amount = calculate_total_amount(amount)
            # 格式化金额为两位小数,符合货币显示规范
            await interaction.user.send(f'Итоговая сумма к оплате: {total_amount:.2f}\nРеквизиты:\n...')

            request_id = generate_request_id()
            payment_channel = bot.get_channel(payment_channel_id)
            if payment_channel:
                await payment_channel.send(
                    f'Запрос на пополнение!\n- user_id: {interaction.user.id}\n'
                    f'- user_balance_wait: {amount}\n- DATE: {current_date()}'
                )
            else:
                await interaction.user.send('Ошибка: не удалось найти канал для отправки запроса администрации')
                return

            save_payment_request(request_id, interaction.user.id, amount)
            await interaction.user.send(
                f'Платеж на рассмотрение. Номер запроса: {request_id}\n'
                f'Ожидайте подтверждения от администрации.'
            )
        except ValueError:
            await interaction.user.send('Пожалуйста, введите корректное число.')

其他优化建议

  1. 数据库操作优化:使用上下文管理器确保数据库连接自动关闭,避免资源泄漏:
def save_payment_request(request_id, user_id, amount):
    try:
        with sqlite3.connect('ezshop_requests.db') as conn_requests:
            cursor_requests = conn_requests.cursor()
            cursor_requests.execute(
                'INSERT INTO requests (requests_id, requests_user_id, requests_user_balance_wait) '
                'VALUES (?, ?, ?)',
                (request_id, user_id, amount)
            )
            conn_requests.commit()
    except sqlite3.Error as e:
        print(f'Ошибка при сохранении запроса: {e}')
  1. 金额计算优化:保留两位小数,避免出现多位小数的不规范显示:
def calculate_total_amount(amount):
    return round(amount * 1.01, 2)
  1. 请求ID唯一性优化:替换随机数为UUID,避免生成重复ID:
import uuid

def generate_request_id():
    return str(uuid.uuid4().int)[:9]  # 取UUID前9位数字,保证唯一性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:13:29