Пагинация Aiogram версии 3

Всем здрасьте, нужна помощь, переписываю свой код под Aiogram 3, мне нужно чтобы можно было листать инлаин кнопки, читал документацию и смотрел примеры, везде под Aiogram 2.

Сейчас вот так:

введите сюда описание изображения

from aiogram.filters.callback_data import CallbackData
from aiogram.utils.keyboard import InlineKeyboardBuilder
from sqlalchemy.ext.asyncio import AsyncSession

from database.function.user_commands import select_allusers, update_status

from filters import PrivateChatFilter

from aiogram import Router, F, types
from aiogram.types import CallbackQuery


router = Router(name='bans')


class Userban(CallbackData, prefix='ban'):
    users_id: int


# РОУТЕР ПО КНОПКЕ ЗАБАНИТЬ
@router.callback_query(F.data.startswith("bans"), PrivateChatFilter())
async def add_ban(call: CallbackQuery, session: AsyncSession):
    await call.answer(cache_time=5)
    users = await select_allusers(session=session)
    kb_users = InlineKeyboardBuilder()
    
    # Добавление айди юзеров в инлаин кнопки
    for user in users:
        kb_users.button(text=f'? {user.user_id}', callback_data=Userban(users_id=user.user_id).pack(), width=2)

    kb_users.row(types.InlineKeyboardButton(text='⬅Назад ', callback_data='cancel'), width=2)
    await call.message.edit_reply_markup(reply_markup=kb_users.as_markup())


@router.callback_query(Userban.filter(F.users_id), PrivateChatFilter())
async def get_ban(call: CallbackQuery, callback_data: Userban, session: AsyncSession):
    await update_status(user_id=callback_data.users_id, session=session, status='banned', commit=True)
    kb_back = InlineKeyboardBuilder()
    kb_back.row(types.InlineKeyboardButton(text='⬅Назад ', callback_data='cancel'), width=1)
    await call.message.edit_text("✅ Вы успешно забанили пользователя", reply_markup=kb_back.as_markup())
    


Ответы (1 шт):

Автор решения: dx3d9

Мне удалось решить свою задачу, я использую Aiogram 3 и SQLAlchemy версии 2. У меня есть файлик user_commands.py в нем у меня выборка к БД PostgreSQL код такой.

async def select_allusers(session):
    query = select(User)  # Предположим, что ваша модель пользователей называется "User"
    result = await session.execute(query)  # Выполнение запроса к базе данных
    users = result.scalars().all()  # Получение списка пользователей
    return users  # Возвращение списка пользователей

Далее файлик bans.py и сам код с комментариями

from aiogram.filters.callback_data import CallbackData  # Импорт класса CallbackData для создания объектов callback data
from aiogram.utils.keyboard import InlineKeyboardBuilder  # Импорт InlineKeyboardBuilder для создания клавиатур
from sqlalchemy.ext.asyncio import AsyncSession  # Импорт AsyncSession для работы с базой данных

from database.function.user_commands import select_allusers, update_status # Импорт функций работы с базой данных

from filters import PrivateChatFilter  # Импорт пользовательского фильтра PrivateChatFilter

from aiogram import Router, F # Импорт основных модулей и классов из aiogram
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton  # Импорт CallbackQuery, InlineKeyboardMarkup и InlineKeyboardButton

router = Router(name='bans')  # Создание роутера с именем 'bans'

# Определение callback data для кнопки бана пользователя
class Userban(CallbackData, prefix='ban'):
    users_id: int  # Поле для идентификатора пользователя

# Определение callback data для навигации по страницам
class Pagination(CallbackData, prefix="pag"):
    action: str  # Действие
    page: int  # Номер страницы

# Функция для создания клавиатуры с пользователями и кнопками для перелистывания
async def paginator(session: AsyncSession, page: int = 0):
    users = await select_allusers(session=session)  # Получение списка пользователей
    builder = InlineKeyboardBuilder()  # Создание объекта InlineKeyboardBuilder
    start_offset = page * 3  # Вычисление начального смещения на основе номера страницы
    limit = 3  # Определение лимита пользователей на одной странице
    end_offset = start_offset + limit  # Вычисление конечного смещения
    for user in users[start_offset:end_offset]:  # Перебор пользователей для текущей страницы
        builder.row(InlineKeyboardButton(text=f'? {user.user_id}', callback_data=Userban(users_id=user.user_id).pack()))  # Добавление кнопки для каждого пользователя
    buttons_row = []  # Создание списка кнопок
    if page > 0:  # Проверка, что страница не первая
        buttons_row.append(InlineKeyboardButton(text="⬅️", callback_data=Pagination(action="prev", page=page - 1).pack()))  # Добавление кнопки "назад"
    if end_offset < len(users):  # Проверка, что ещё есть пользователи для следующей страницы
        buttons_row.append(InlineKeyboardButton(text="➡️", callback_data=Pagination(action="next", page=page + 1).pack()))  # Добавление кнопки "вперед"
    else:  # Если пользователи закончились
        buttons_row.append(InlineKeyboardButton(text="➡️", callback_data=Pagination(action="next", page=0).pack()))  # Возвращение на первую страницу
    builder.row(*buttons_row)  # Добавление кнопок навигации
    builder.row(InlineKeyboardButton(text='⬅️ Назад', callback_data='cancel'))  # Добавление кнопки "назад"
    return builder.as_markup()  # Возвращение клавиатуры в виде разметки

# Обработчик нажатия на кнопку "бан" для пользователя
@router.callback_query(F.data.startswith("bans"), PrivateChatFilter())
async def add_ban(call: CallbackQuery, session: AsyncSession):
    await call.answer()  # Отправка ответа на запрос
    await call.message.edit_reply_markup(reply_markup=await paginator(session=session, page=0))  # Отображение клавиатуры с пользователями и кнопками для перелистывания

# Обработчик нажатия кнопок навигации
@router.callback_query(Pagination.filter(), PrivateChatFilter())
async def pagination_handler(call: CallbackQuery, callback_data: Pagination, session: AsyncSession):
    page = callback_data.page  # Получение номера страницы из callback data
    await call.message.edit_reply_markup(reply_markup=await paginator(session=session, page=page))  # Обновление клавиатуры при нажатии кнопок "вперед" или "назад"

# Обработчик нажатия кнопок бана для конкретного пользователя
@router.callback_query(Userban.filter(), PrivateChatFilter())
async def get_ban(call: CallbackQuery, callback_data: Userban, session: AsyncSession):
    await update_status(user_id=callback_data.users_id, session=session, status='banned', commit=True)  # Обновление статуса пользователя на "забанен" в базе данных
    kb_back = InlineKeyboardBuilder()  # Создание клавиатуры
    kb_back.row(InlineKeyboardButton(text='⬅️ Назад', callback_data='cancel'))  # Добавление кнопки "назад"
    await call.message.edit_text("✅ Вы успешно забанили пользователя", reply_markup=kb_back.as_markup())  # Отправка сообщения об успешном бане пользователя
→ Ссылка