@liss48

Python, VKBottle, SQL. Как ограничить доступ к команде на время?

Есть такой код:

@bot.on.chat_message(text='r')
async def r(message: Message):

    user = await bot.api.users.get(message.from_id)

    with connection.cursor() as cursor:
        cursor.execute(f"UPDATE inf SET time = '{datetime.datetime.now()}' WHERE id = '{user[0].id}'")
        connection.commit()

        cursor.execute(f"SELECT time FROM inf WHERE id = '{user[0].id}'")

        last_command_use_time = cursor.fetchone()

    if not last_command_use_time or (datetime.datetime.now() - last_command_use_time).seconds > 10:
        await message.answer(f'RRR')

        with connection.cursor() as cursor:
            cursor.execute(f"UPDATE inf SET time = '{datetime.datetime.now()}' WHERE id = '{user[0].id}'")
            connection.commit()

    else:
        await message.answer(f'[id{user[0].id}|{user[0].first_name}], Команду можно вызывать только раз в 10 секунд!')


Я хочу сохранять время последней команды каждого пользователя в бд и каждый раз проверять прошло ли 10 секунд. По идее все должно работать но при высчитывании времени вылезает ошибка типов данных которую я не знаю как исправить:
TypeError: unsupported operand type(s) for -: 'datetime.datetime' and 'tuple'
  • Вопрос задан
  • 130 просмотров
Решения вопроса 2
Vindicar
@Vindicar
RTFM!
1. НИКОГДА не формируй запросы f-строками. Учись пользоваться parametrized queries. В твоём случае особого риска нет, но лучше сразу приучаться делать правильно.
2. cursor.fetchone() ВСЕГДА возвращает кортеж, даже если ты запрашиваешь один элемент. В твоём случае это будет кортеж из одного элемента с индексом 0. Как работать с кортежами - гуглим.
Ответ написан
drygdryg
@drygdryg
Python-разработчик
В этой строке метод fetchone() возвращает один результат в виде кортежа полей, в вашем случае состоящего из одного элемента — значения поля time:
last_command_use_time = cursor.fetchone()
Поэтому вы можете извлечь из него первый элемент и положить его в last_command_use_time:
last_command_use_time = cursor.fetchone()[0]
Никогда не используйте f-строки или иной способ форматирования для подстановки значений в SQL-запросы: это может вызвать проблемы с безопасностью приложения. Как верно отметил Vindicar, лучше использовать средства вашего драйвера СУБД для подстановки параметров в запросы (parametrized quieries).
К тому же, для ограничения частоты выполнения каких-либо действий в вашем приложении обычно лучше использовать решения на базе быстрых хранилищ "ключ-значение" вроде Redis или Memcached, чем на базе реляционных СУБД (коей является PostgreSQL).
Советую обратить внимание на инструмент PyrateLimiter: он обеспечивает ограничение частоты выполнения функции (либо корутины, что может быть полезным в вашем случае) и в качестве хранилища может использовать оперативную память (queue.Queue), Redis или SQLite.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы