Диалоги и состояния
Создание напоминания — это диалог: что напомнить? через сколько? Бот должен помнить, на каком шаге пользователь и что он уже ответил. Для этого в aiogram есть машина состояний (FSM).
Состояния
from aiogram.fsm.state import State, StatesGroup
class New(StatesGroup):
text = State() # ждём текст напоминания
minutes = State() # ждём число минут
FSMContext
Добавьте в обработчик параметр state: FSMContext — aiogram передаст «память» этого пользователя в этом чате:
from aiogram.fsm.context import FSMContext
@router.message(Command("new"))
async def start(message: Message, state: FSMContext):
await state.set_state(New.text)
await message.answer("Что напомнить?")
@router.message(New.text) # только в состоянии New.text
async def got_text(message: Message, state: FSMContext):
await state.update_data(text=message.text)
await state.set_state(New.minutes)
await message.answer("Через сколько минут?")
@router.message(New.minutes)
async def got_minutes(message: Message, state: FSMContext):
data = await state.get_data() # {"text": "…"}
await state.clear() # диалог окончен
await message.answer(f"Готово: {data['text']}")
set_state(…)— перейти на шаг;get_state()— текущий шаг (Noneвне диалога);update_data(ключ=значение)— запомнить,get_data()— словарь всего запомненного;clear()— забыть и состояние, и данные. Не забывайте его в конце диалога: иначе бот так и будет считать каждое сообщение ответом на последний вопрос.
Неверный ответ
Если ответ не подходит — не меняйте состояние, просто переспросите. Пользователь останется на том же шаге.
Отмена
Пользователь должен иметь возможность выйти из диалога. Обработчик без фильтра состояния работает в любом состоянии, поэтому /cancel регистрируют раньше обработчиков шагов — иначе шаг перехватит «/cancel» как обычный ответ.
Где хранится память
По умолчанию Dispatcher хранит состояния в памяти процесса (MemoryStorage): после перезапуска бота все диалоги забудутся. В настоящих ботах берут RedisStorage — состояния переживают перезапуски.
Итог
StatesGroupиState; фильтр по состоянию в декораторе;state.set_state,get_state,update_data,get_data,clear;- неверный ответ — переспросить, не меняя шага;
/cancel— раньше обработчиков шагов.