Topic 4 of 6

Course materials are currently available in Russian only.

Кнопки и колбэки

Набирать команды неудобно. Гораздо приятнее нажимать кнопки — в aiogram для этого есть инлайн-клавиатуры под сообщениями.

Клавиатура

from aiogram.utils.keyboard import InlineKeyboardBuilder

builder = InlineKeyboardBuilder()
for m in [5, 10, 15, 30]:
    builder.button(text=f"{m} мин", callback_data=f"in:{m}")
builder.button(text="Отмена", callback_data="cancel")
builder.adjust(2, 2, 1)                    # ряды: 2, 2 и 1 кнопка
await message.answer("Через сколько?", reply_markup=builder.as_markup())
  • text — надпись на кнопке, callback_data — строка (до 64 байт), которую бот получит при нажатии;
  • adjust(…) раскладывает кнопки по рядам; последнее число повторяется для оставшихся кнопок;
  • кнопка-ссылка — builder.button(text="Сайт", url="https://…").

Бывают ещё «обычные» клавиатуры вместо поля ввода (ReplyKeyboardBuilder) — их нажатия приходят как текстовые сообщения.

Нажатие

from aiogram.types import CallbackQuery


@router.callback_query(F.data.startswith("in:"))
async def picked(callback: CallbackQuery):
    minutes = int(callback.data.split(":")[1])
    await callback.message.edit_text(f"Напомню через {minutes} мин")
    await callback.answer("Принято!")
  • нажатие приходит как CallbackQuery: callback.data — данные кнопки, callback.from_user — кто нажал, callback.message — сообщение с кнопками;
  • callback.message.edit_text(…, reply_markup=…) меняет само сообщение — так делают листалки и меню;
  • await callback.answer() обязателен: иначе на кнопке у пользователя долго крутятся часики. С текстом — всплывающее уведомление.

Фабрика данных

Склеивать и разбирать строки вручную легко с ошибкой. Для этого есть CallbackData:

from aiogram.filters.callback_data import CallbackData


class ReminderCb(CallbackData, prefix="rem"):
    action: str
    rid: int


kb.button(text="Готово", callback_data=ReminderCb(action="done", rid=3))   # "rem:done:3"


@router.callback_query(ReminderCb.filter(F.action == "done"))
async def done(callback: CallbackQuery, callback_data: ReminderCb):
    callback_data.rid        # 3 — уже число

Фабрика сама собирает строку и разбирает её обратно, с проверкой типов. Фильтр .filter(...) пропускает только данные с этим префиксом и нужными значениями.

Итог

  • InlineKeyboardBuilder, button(text, callback_data), adjust, as_markup();
  • @router.callback_query(...), callback.data, edit_text;
  • await callback.answer() — всегда;
  • фабрика CallbackData с prefix и полями, .filter(...).