Не получается переписать код дискорд бота с использованием PostgreSQL

Я пишу дискород бота, который при включении или присоединении пользователя к серверу должен добавлять его в бд. В начале в качестве бд я использовал sqlite3, но после того как залил бота на Heroku и столкнулся с тем, что данные стираются спустя какое-то время, узнал что Heroku не использует sqlite3, и поэтому мне нужно использовать PostgreSQL. Вот мой старый код с sqlite3:

connect = sqlite3.connect("server.dp")
cursor = connect.cursor()

@bot.event
async def on_ready():
    """Функция on_ready выполняется при запуске бота и создаёт таблицу users
    в бд, также добавляет в бд имена, id, количество xp и сервер всех
    участников, которых нет в бд.
    """
    DiscordComponents(bot)
    cursor.execute("""CREATE TABLE IF NOT EXISTS users (
        name TEXT,
        id INT,
        xp 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:
                if member.id not in bots:
                    cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0)")
    connect.commit()
    print("Bot connected!")


@bot.event
async def on_member_join(member):
    """Функция on_member_join добавляет в бд имя, id, количество
    xp и сервер пользователя, если его ещё нет в бд.
    """
    if cursor.execute(f"SELECT id from users WHERE id = {member.id}").fetchone()[0] is None:
        cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0, {member.guild.id})")
        connect.commit()

А вот моя попытка переделать это на PostgreSQL:

connect = psycopg2.connect(db_uri, sslmode="require")
cursor = connect.cursor()

@bot.event
async def on_ready():
    """Функция on_ready выполняется при запуске бота и создаёт таблицу users
    в бд, также добавляет в бд имена, id, количество xp и сервер всех
    участников, которых нет в бд.
    """
    DiscordComponents(bot)
    cursor.execute("""CREATE TABLE IF NOT EXISTS users (
        name TEXT,
        id INT,
        xp 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:
                if member.id not in bots:
                    cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0)")
    connect.commit()
    print("Bot connected!")


@bot.event
async def on_member_join(member):
    """Функция on_member_join добавляет в бд имя, id, количество
    xp и сервер пользователя, если его ещё нет в бд.
    """
    if cursor.execute(f"SELECT id from users WHERE id = {member.id}").fetchone()[0] is None:
        cursor.execute(f"INSERT INTO users VALUES ('{member}', {member.id}, 0, {member.guild.id})")
        connect.commit()

В connect = psycopg2.connect(db_uri, sslmode="require") я подключаю бд из Heroku (созданной с помощью аддона Heroku Postgres) Но при попытке запуска бота получаю такую ошибку:

Ignoring exception in on_ready
Traceback (most recent call last):
  File "C:\Users\belog\hat_dispenser\venv\lib\site-packages\discord\client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "C:\Users\belog\hat_dispenser\main.py", line 56, in on_ready
    if cursor.execute(f"SELECT id FROM users WHERE id = {member.id}").fetchone() is None:
AttributeError: 'NoneType' object has no attribute 'fetchone'

Как это исправить?


Ответы (1 шт):

Автор решения: Be3y4uu_K0T

Выдержка из документации.

execute(query, vars=None)

Execute a database operation (query or command).

Parameters may be provided as sequence or mapping and will be bound to variables in the operation. Variables are specified either with positional (%s) or named (%(name)s) placeholders. See Passing parameters to SQL queries.

The method returns None. If a query was executed, the returned values can be retrieved using fetch*() methods.

Это значит, что Вы должны сначала выполнить запрос cursor.execute(). А потом отдельно получить результат через cursor.fetchone() ссылка.

Пример из документации:

>>> cur.execute("SELECT * FROM test WHERE id = %s", (3,))
>>> cur.fetchone()
(3, 42, 'bar')
→ Ссылка