Как использовать подтверждение о доставке колбэка
Делаю пагинацию страниц. При сценарии страница1-страница2-страница1-страница2 инлайн-кнопка на страницу2 во второй итерации не нажимается (нет никакого отклика). Если убрать подтверждение о доставке колбэка, вроде все получается корректно, но при быстром нажатии кнопок вылетает в ошибку. Помогите разобраться.
# обработчик команды "numbers"
@dp.message_handler(text='/numbers')
async def cmd_numbers_command(message: types.Message):
closest_points = ('страница 1', 'страница 2', 'страница 3')
page = 0
count_page = len(closest_points)
text = closest_points[page]
# собрали клавиатуру
markup = pro_inline(page, count_page, message.from_user.id)
await message.answer(f"{text}", reply_markup=markup)
# коллбэк от инлайн кнопки
@dp.callback_query_handler(pages_callback.filter())
async def callbacks_num(call: types.CallbackQuery, callback_data: dict):
# подтверждение о доставке колбэка
await call.answer(cache_time=60)
closest_points = ('страница 1', 'страница 2', 'страница 3')
count_page = int(callback_data.get("count"))
page = int(callback_data.get("page"))
id_user = int(callback_data.get("id_user"))
direction = callback_data.get("direction")
if direction == "finish":
await call.message.edit_reply_markup()
else:
markup = pro_inline(page, count_page, id_user)
text = str(closest_points[page])
await call.message.edit_text(f"{text}", reply_markup=markup)
файл keyboards.py
def pro_inline(page, count, id):
btn1 = InlineKeyboardButton(text='<--', callback_data=f"pages:back:{page - 1}:{count}:{id}")
btn2 = InlineKeyboardButton(text=f'{page + 1}' + '/' + f'{count}',
callback_data=f"pages:null:{page}:{count}:{id}")
btn3 = InlineKeyboardButton(text='-->', callback_data=f"pages:next:{page + 1}:{count}:{id}")
btn4 = InlineKeyboardButton(text='Отмена', callback_data=f"pages:finish:{page}:{count}:{id}")
if page == 0:
buttons = [[btn2, btn3], [btn4]]
elif page == count - 1:
buttons = [[btn1, btn2], [btn4]]
else:
buttons = [[btn1, btn2, btn3], [btn4]]
kb = InlineKeyboardMarkup(inline_keyboard=buttons)
return kb
файл callback_data.py
pages_callback = CallbackData("pages", "direction", "page", "count", "id_user")
Ответы (1 шт):
Проблема может возникать из-за того, что при быстром нажатии кнопок, вызываются несколько обработчиков коллбэков, и может произойти некоторое взаимодействие между ними, что приводит к неожиданным результатам.
Один из способов решения этой проблемы состоит в том, чтобы сделать кнопки неактивными во время обработки события коллбэка. Для этого можно использовать атрибут callback_data для хранения состояния кнопки, чтобы заблокировать ее повторное использование, пока обрабатывается текущее событие коллбэка.
пример кода, который может помочь:
# добавляем данные о состоянии кнопки в атрибут callback_data
btn1 = InlineKeyboardButton(text='<--', callback_data=f"pages:back:{page - 1}:{count}:{id}:inactive")
btn2 = InlineKeyboardButton(text=f'{page + 1}' + '/' + f'{count}',
callback_data=f"pages:null:{page}:{count}:{id}:inactive")
btn3 = InlineKeyboardButton(text='-->', callback_data=f"pages:next:{page + 1}:{count}:{id}:inactive")
btn4 = InlineKeyboardButton(text='Отмена', callback_data=f"pages:finish:{page}:{count}:{id}:inactive")
# колбэк для обработки кнопок с атрибутом "inactive"
@dp.callback_query_handler(lambda c: c.data and c.data.endswith(":inactive"))
async def inactive_callback_handler(call: CallbackQuery):
await call.answer(text="Кнопка заблокирована", show_alert=True)
# коллбэк для обработки активных кнопок
@dp.callback_query_handler(pages_callback.filter())
async def callbacks_num(call: types.CallbackQuery, callback_data: dict):
# подтверждение о доставке колбэка
await call.answer(cache_time=60)
# извлекаем состояние кнопки
button_state = callback_data.get("state", "active")
if button_state == "inactive":
# игнорируем обработку колбэка, если кнопка заблокирована
return
# извлекаем остальные данные
closest_points = ('страница 1', 'страница 2', 'страница 3')
count_page = int(callback_data.get("count"))
page = int(callback_data.get("page"))
id_user = int(callback_data.get("id_user"))
direction = callback_data.get("direction")
# обновляем состояние кнопок
markup = pro_inline(page, count_page, id_user, inactive_buttons=[direction])
if direction == "finish":
await call.message.edit_reply_markup()
else:
text = str(closest_points[page])
await call.message.edit_text(f"{text}", reply_markup=markup)
Обратите внимание, что мы добавляем новый параметр inactive_buttons в функцию pro_inline, который принимает список направлений кнопок, которые нужно заблокировать.