aiogram 3.13.1 Как сделать последовательное выполнение функций
Бот запрашивает текст(данные) от юзера, затем должен выполнить функцию
При вводе команды от юзера, у меня выполняется фукнкция, которая отправляет текст "Введите свой ID", а затем после ввода юзера должна выполняться следующая функция уже с кодом обработки (код рабочий, я просто связать не могу эти функции)
В pytelegram через bot.register_next_handler()
было проще
Ответы (1 шт):
Для таких вещей в 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)