I wrote a Telegram bot.
Basis: Aiogram
Database: postgreSQL + Django admin panel
Problem: The first time users press /start
to use the bot (which adds the user's information to the database), the bot works fine, but after that, when a user added to the database presses /start
2nd time while using the bot, the following error occurs.
from typing import Union
import asyncpg
from asyncpg import Connection
from asyncpg.pool import Pool
from data import config
class Database:
def __init__(self):
self.pool: Union[Pool, None] = None
async def create(self):
self.pool = await asyncpg.create_pool(
user=config.DB_USER,
password=config.DB_PASS,
host=config.DB_HOST,
database=config.DB_NAME
)
async def execute(self, command, *args,
fetch: bool = False,
fetchval: bool = False,
fetchrow: bool = False,
execute: bool = False
):
async with self.pool.acquire() as connection:
connection: Connection
async with connection.transaction():
if fetch:
result = await connection.fetch(command, *args)
elif fetchval:
result = await connection.fetchval(command, *args)
elif fetchrow:
result = await connection.fetchrow(command, *args)
elif execute:
result = await connection.execute(command, *args)
return result
@staticmethod
def format_args(sql, parameters: dict):
sql += " AND ".join([
f"{item} = ${num}" for num, item in enumerate(parameters.keys(),
start=1)
])
return sql, tuple(parameters.values())
async def add_user(self, full_name, username, telegram_id):
sql = "INSERT INTO usersinfo_user (full_name, username, telegram_id) VALUES($1, $2, $3) returning *"
return await self.execute(sql, full_name, username, telegram_id, fetchrow=True)
async def select_all_users(self):
sql = "SELECT * FROM usersinfo_user"
return await self.execute(sql, fetch=True)
async def select_user(self, **kwargs):
sql = "SELECT * FROM usersinfo_user WHERE"
sql, parameters = self.format_args(sql, parameters=kwargs)
return await self.execute(sql, *parameters, fetchrow=True)
async def count_users(self):
sql = "SELECT COUNT(*) FROM usersinfo_user"
return await self.execute(sql, fetchval=True)
async def update_user_username(self, username, telegram_id):
sql = "UPDATE usersinfo_user SET username=$1 WHERE telegram_id=$2"
return await self.execute(sql, username, telegram_id, execute=True)
async def delete_users(self):
await self.execute("DELETE FROM usersinfo_user WHERE TRUE", execute=True)
async def drop_users(self):
await self.execute("DROP TABLE usersinfo_user", execute=True)
import logging
import asyncpg.exceptions
from aiogram import types
from aiogram.dispatcher.filters.builtin import CommandStart
from data.config import ADMINS
from keyboards.inline.languageKeyboard import choose_language
from states.intro import IntroState
from loader import dp, db, bot
@dp.message_handler(CommandStart(), state=None)
async def bot_start(message: types.Message):
try:
user = await db.add_user(telegram_id=message.from_user.id,
full_name=message.from_user.full_name,
username=message.from_user.username)
except asyncpg.exceptions.UniqueViolationError:
user = await db.select_user(telegram_id=message.from_user.id)
await message.answer("Choose language:", reply_markup=choose_language)
await IntroState.language.set()
logging.info(message)
# Notify admin about added usr
count = await db.count_users()
msg = f"User<b>{user[1]}</b> added.\n All users:<b>{count}</b> ."
await bot.send_message(chat_id=ADMINS[0], text=msg)
from aiogram import executor
from loader import dp, db
import middlewares, filters, handlers
from utils.notify_admins import on_startup_notify
from utils.set_bot_commands import set_default_commands
async def on_startup(dispatcher):
await db.create()
# Commands
await set_default_commands(dispatcher)
# Notify admin
await on_startup_notify(dispatcher)
if __name__ == '__main__':
executor.start_polling(dp, on_startup=on_startup)
try with ON CONFLICT :
sql = "INSERT INTO vegabot.Resume (telegram_id, language, fullname) VALUES($1, $2, $3) ON CONFLICT (telegram_id) DO NOTHING RETURNING *"