aiogram 3.13.1 Как сделать последовательное выполнение функций

Бот запрашивает текст(данные) от юзера, затем должен выполнить функцию

При вводе команды от юзера, у меня выполняется фукнкция, которая отправляет текст "Введите свой ID", а затем после ввода юзера должна выполняться следующая функция уже с кодом обработки (код рабочий, я просто связать не могу эти функции)

В pytelegram через bot.register_next_handler() было проще


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

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

Для таких вещей в aiogram используется машина состояний.

Код будет выглядеть следующим образом:

import asyncio

from aiogram import Dispatcher, Bot, Router

from aiogram.types import Message
from aiogram.filters import StateFilter
from aiogram.fsm.context import FSMContext


from aiogram.fsm.state import State, StatesGroup

# Класс состояний бота
class BotStates(StatesGroup):
    entering_id = State() # Состояние ввода ID

# Роутер, с помощью которого будем регестрировать наши хендлеры
router = Router()

# Добавляем в роутер обработчик сообщения
@router.message(
    Command("start"),  # Этот обработчик будет принимать команду /start
    StateFilter(None)  # И будет срабатывать при отсутствии состояния 
)
async def start_command(message: Message, state: FSMContext):
    await state.set_state(BotStates.entering_id) # Выставляем состояние
    await message.answer("Введите свой ID")


# Следующий обработчик сообщений будет принимать сообщения только если выставлено состояние BotStates.entering_id
@router.message(
    StateFilter(BotStates.entering_id) # Фильтрация по состоянию BotStates.entering_id
)
async def processing_code(message: Message, state: FSMContext):
    processing_code = await process_message(message.text) # Текст, который ввел пользователь после сообщения "Введите свой ID"
    await state.set_state(None) # Убираем состояние 
    await message.answer(processing_code)

# Функция-обработчик пользовательского сообщения
# вызываем с ключевым словом await, так как она асинхронная
async def process_message(text: str) -> str:
    # Обработка сообщения пользователя
    return text

# Запуск бота
async def main():
    bot = Bot("ваш токен")
    dp = Dispatcher()

    dp.include_router(router)

    await bot.delete_webhook(drop_pending_updates=True) # Удаляем все обновления
    await dp.start_polling(bot)


if __name__ == "__main__":
    asyncio.run(main())

Как это работает

Ключевым моментом тут является работа с машиной состояний.
Состояние можно упрощенно описать, как некая глобальная переменная. Мы можем менять ее значение и проверять его при входе в хендлер.

При запуске бот у нас находится в состоянии None

Строчкой:

await state.set_state(BotStates.entering_id)

Мы переводим его в состояние BotStates.entering_id. Далее, в хендлере processing_code мы выставляем критерий StateFilter(BotStates.entering_id). Это значит, что этот хендлер будет принимать сообщения только тогда, когда состояние бота будет BotStates.entering_id.

И далее возвращаем бота к нулевому состоянию:

await state.set_state(None)
→ Ссылка