Cat

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

В этом посте покажу пример создания кнопок пагинации в aiogram 3.

Tips & Tricks proDream 26 Август 2024 Просмотров: 371

Меню в 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)  
)

 

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

Автор

  • 2 октября 2024 г. 17:58

    len_list - содержимого переменной нет. len(products) нужен

  • Реклама