Discord бот не добавляет пользователей в бд
Я пишу discord бота (discord.py) на python, в котором будет рейтинговая система. Когда пользователь присоединяется к серверу, бот должен автоматически записывать его в бд (sqlite3), а если я отмечаю его сообщения реакцией (например ✅), бот должен прибавлять пользователю 500 очков в бд. Но когда я со 2 аккаунта присоединяюсь к серверу, бот не добавляет меня в бд, при вызове команды /top не отображает меня в списке пользователей, а команда /points выдаёт такую ошибку:
Ignoring exception in command points:
Traceback (most recent call last):
File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
ret = await coro(*args, **kwargs)
File "C:\Users\belog\hat_dispenser\main.py", line 75, in points
xp = cursor.execute(f"""SELECT points FROM users WHERE id = {ctx.author.id}""").fetchone()[0]
TypeError: 'NoneType' object is not subscriptable
Вот код:
import re
import sqlite3
import discord
from discord.ext import commands
from discord_components import DiscordComponents, Button, ButtonStyle
from config import settings
bot = commands.Bot(command_prefix=settings['prefix'], intents=discord.Intents.default())
connect = sqlite3.connect("server.dp")
cursor = connect.cursor()
@bot.event
async def on_ready():
DiscordComponents(bot)
cursor.execute("""CREATE TABLE IF NOT EXISTS users (
name TEXT,
id INT,
points INT
)""")
for guild in bot.guilds:
for member in guild.members:
if cursor.execute(f"SELECT id FROM users WHERE id = {member.id}").fetchone() is None:
cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0)")
else:
pass
connect.commit()
print("Bot connected!")
@bot.event
async def on_member_join(member):
if cursor.execute(f"SELECT id from users WHERE id = {member.id}").fetchone() is None:
cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0)")
connect.commit()
@bot.event
async def on_raw_reaction_add(payload):
channel = bot.get_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
guild = bot.get_guild(payload.guild_id)
reaction = discord.utils.get(message.reactions, emoji=payload.emoji.name)
if payload.member.id == bot.user.id:
pass
elif payload.member.id == 633717285474795557 and str(reaction.emoji) == '✅':
cursor.execute(f"UPDATE users SET points = points + 500 WHERE id = {payload.member.id}")
connect.commit()
@bot.command()
async def points(ctx, member: discord.Member = None):
if member:
xp = cursor.execute(f"""SELECT points FROM users WHERE id = {ctx.author.id}""").fetchone()[0]
await ctx.send(f"У пользователя **{member.mention} {xp}XP**")
else:
xp = cursor.execute(f"""SELECT points FROM users WHERE id = {ctx.author.id}""").fetchone()[0]
await ctx.send(f"У вас **{xp}XP**")
@bot.command()
async def top(ctx):
users = []
user_xp = list(cursor.execute(f"SELECT points FROM users").fetchall())
top_users = {}
for user in [user for user in list(cursor.execute("SELECT name FROM users").fetchall())]:
users.append(re.sub("[)|(,']", "", str(user)))
top_users = dict(zip(users, user_xp))
sorted_values = sorted(top_users.values())
sorted_top_users = {}
for val in sorted_values:
for key in top_users.keys():
if top_users[key] == val:
sorted_top_users[key] = top_users[key]
break
top_str = ""
counter = 0
for name, xp in sorted(list(sorted_top_users.items())):
counter += 1
top_str += f"{counter} - {name}: {list(xp)[0]}XP\n"
emb = discord.Embed(title="Топ участников по колличеству XP:", colour=discord.Colour.green(),
description=f"**{top_str}**")
await ctx.send(embed=emb)
bot.run(settings['token'])
Ответы (3 шт):
Сравните id (или имена) авторов сообщения. Они будут разные. Один это бот, второй это пользователь.
В данном случае надо просто создавать пользователя если его нет.
В функции points ветвление идет по пути else и пытается получить пользователя по id которого нет в БД. .fetchone() вернет None у которого при попытке получить что либо по индексу возникнет TypeError.
Возможно ваше событие on_member_join не срабатывает из-за того, что у Вас intents=discord.Intents.default(). Потому что (выдержка из документации)
A factory method that creates a :class:
Intentswith everything enabled except :attr:presencesand :attr:members.
Whether guild presence related events are enabled.
This corresponds to the following events:
- on_member_update() (activities, status)
This also corresponds to the following attributes and classes in terms of cache:
- Member.activities
- Member.status
- Member.raw_status
Intents.membersWhether guild member related events are enabled.This corresponds to the following events:
- on_member_join()
- on_member_remove()
- on_member_update() (nickname, roles)
- on_user_update()
This also corresponds to the following attributes and classes in terms of cache:
- Client.get_all_members()
- Guild.chunk()
- Guild.fetch_members()
- Guild.get_member()
- Guild.members
- Member.roles
- Member.nick
- Member.premium_since
- User.name User.avatar (User.avatar_url and User.avatar_url_as())
- User.discriminator
Это означает, что события просто не вызывается!
В документации в разделе A Primer to Gateway Intents решение Вашей проблемы описано: ссылка
from discord.ext import commands
import discord
intents = discord.Intents.default()
intents.members = True
bot = commands.Bot(command_prefix='!', intents=intents)
Причина в том, что забыли добавить connect.commit():
for guild in bot.guilds:
for member in guild.members:
if cursor.execute(f"SELECT id FROM users WHERE id = {member.id}").fetchone() is None:
cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0)")
else:
pass