Пагинация в aiogram 3

Пагинация в aiogram 3

Иван Ашихмин

Пост на сайте

Поддержать проект на Boosty

Поддержать проект в Telegram

Меню в Telegram-ботах является важной частью взаимодействия с пользователем. Но, что делать, когда элементов меню много и выводить их "портянкой" из кнопок не совсем удобно? На помощь приходит привычная нам пагинация - переключение страниц, а в случае с ботом, набора кнопок.

Представим, что у нас есть некая функция, возвращающая список товаров. В этом списке 20 элементов, а мы хотим выводить по пять штук. Получается, нам нужно четыре страницы.

Сперва создадим коллбэк-класс Pagination:

class Pagination(CallbackData, prefix="pag"): 
page: int

В этом классе прописываем поле page - номер страницы.

Затем создаём клавиатуру, выводящую пять элементов из списка. Также в зависимости от того какая сейчас страница две кнопки:

  • Если первая, то добавляем только кнопку вперёд.
  • Если не первая и не последняя, то две кнопки вперёд и назад.
  • Если последняя, то только кнопку назад.
async def get_paginated_kb(page: int = 0) -> InlineKeyboardMarkup: 
builder = InlineKeyboardBuilder()

products = await get_products()
start_offset = page * 5
end_offset = start_offset + 5

for product in products[start_offset:end_offset]:
builder.row(InlineKeyboardButton(text=product.title, callback_data=ProductData(id=product.id).pack()))

buttons_row = []
if page > 0:
buttons_row.append(
InlineKeyboardButton(
text="⬅️",
callback_data=Pagination(page=page - 1).pack(),
)
)
if end_offset < len_list:
buttons_row.append(
InlineKeyboardButton(
text="➡️",
callback_data=Pagination(page=page + 1).pack(),
)
)
builder.row(*buttons_row)

return builder.as_markup()

В коде выше мы задали начальное смещение start_offset и конечное end_offset, благодаря им, будем получать из списка только нужные элементы.

Затем создаём два простых обработчика.
Первый срабатывает при выполнении команды /products и выводит сообщение с кнопками товаров.
Второй будет реагировать на нажатия кнопок пагинации и изменять исходное сообщение, выдавая другие товары.

@products_router.message(Command(commands=["products"])) 
async def send_products_handler(message: Message):
await message.answer(
text="Список товаров:",
reply_markup=await get_paginated_kb(),
)

@products_router.callback_query(Pagination.filter())
async def products_pagination_callback(callback: CallbackQuery, data: Pagination):
page = data.page
await callback.message.edit_reply_markup(
reply_markup=await get_paginated_kb(page=page)
)

Таким образом в боте можно будет переключаться между страницами с товаром. И конечно же напомню, что это всего лишь пример и реализация в вашем проекте может отличаться.

Пост на сайте

Поддержать проект на Boosty

Поддержать проект в Telegram

Report Page