How to fix this problem with inline buttons pagination on aiogram 3.0?

309 views Asked by At

I have an inline button pagination and a database. text[0], callbackdata1 I need them to be output five pieces(and so until the database runs out, it can have at least 100 elements) in turn, but I just have the first element repeated five times,then also the second, third, and so on

cur.execute("SELECT * FROM data")
data = cur.fetchall()


def paginator(page: int=0):
builder = InlineKeyboardBuilder()
for i in range(5):
    button = InlineKeyboardButton(text=data[page][0], callback_data=data[page][1])

    builder.add(button)
    builder.adjust(1)
builder.row(
    InlineKeyboardButton(text="⬅", callback_data=kb.Pagination(action="prev", page=page).pack()),
    InlineKeyboardButton(text="➡", callback_data=kb.Pagination(action="next", page=page).pack()),
    width=2
)
return builder.as_markup()



@dp.callback_query(kb.Pagination.filter(F.action.in_(["prev", "next"])))
async def pagination_handler(call: CallbackQuery, callback_data: kb.Pagination):
    page_num = int(callback_data.page)
    page = page_num - 1 if page_num > 0 else 0

    if callback_data.action == "next":
        page = page_num + 1 if page_num < (len(data) - 1) else page_num

    with suppress(TelegramBadRequest):
        await call.message.edit_text(
            f"list",
            reply_markup=paginator(page)
        )
    await call.answer()


@dp.message()
async def echo(message: Message):
    msg = message.text.lower()

    if msg == "list":
        await message.answer("lis", reply_markup=paginator(0))

enter image description here

1

There are 1 answers

0
Dmitriy On

As I understand both of our solutions are based on the same code, so that's how I did that, it may be helpful:

class Pagination(CallbackData, prefix='pag'):
    action: str
    page: int


def paginator(page: int = 0):
    builder = InlineKeyboardBuilder()
    builder.row(
        InlineKeyboardButton(text='⬅', callback_data=Pagination(action='prev', page=page).pack()),
        InlineKeyboardButton(text='➡', callback_data=Pagination(action='next', page=page).pack()),
        width=2
    )
    return builder


@router.callback_query(Teacher(), CourseInteract.pagination, Pagination.filter(F.action.in_(('prev', 'next'))))
async def pagination_handler(query: CallbackQuery, callback_data: Pagination, session: AsyncSession, state: FSMContext):
    course_id = await state.get_data()
    stmt = select(Publications).where(Publications.course == course_id['course'])
    res = await session.execute(stmt)
    posts = res.scalars().all()
page_num = int(callback_data.page)

if callback_data.action == 'next':
    if page_num < (len(posts) // 5):
        page = page_num + 1
    else:
        page = page_num
        await query.answer('This is the last page')
else:
    if page_num > 0:
        page = page_num - 1
    else:
        page = 0
        await query.answer('This is the first page')

with suppress(TelegramBadRequest):
    pag = paginator(page)
    builder = InlineKeyboardBuilder()
    start_index = page * 5
    end_index = min(start_index + 5, len(posts))

    for i in range(start_index, end_index):
        builder.row(InlineKeyboardButton(text=posts[i].title,
                                         callback_data=f'publication_{posts[i].id}'))

    builder.row(*pag.buttons, width=2)
    await query.message.edit_reply_markup(reply_markup=builder.as_markup())
    await query.answer()

And to display the first 5 records from your query you should do something like that:

#here must be an SQL query or something
    if posts:
            pag = paginator()
            builder = InlineKeyboardBuilder()
            num = 0
            for post in posts:
                if num < 5:
                    num += 1
                    builder.row(InlineKeyboardButton(text=post.title, callback_data=f'publication_{post.id}'))
    
            builder.row(*pag.buttons, width=2)
            await state.set_state(CourseInteract.pagination)
            await message.answer('Here is publications:', reply_markup=builder.as_markup())