Skip to content
Maksym Zavalniuk edited this page Sep 8, 2023 · 2 revisions

How to work with the state machine?

  1. Create a class in the states/states.py folder:
from aiogram.fsm.state import State, StatesGroup


class OrderFood(StatesGroup):
    choosing_food_name = State()
    choosing_food_size = State()
  1. Update your handler:
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import Message, ReplyKeyboardRemove

from loader import dp
from tgbot.keyboards.reply.food_keyboard import make_row_keyboard
from tgbot.states.states import OrderFood

router = Router()
dp.include_router(router)

FOOD_NAMES = ["Sushi", "Spaghetti", "French fries"]
FOOD_SIZES = ["Mini", "Small", "Large"]


@router.message(Command("food"))
async def cmd_food(message: Message, state: FSMContext):
    await message.answer(
        text="Choose food:",
        reply_markup=make_row_keyboard(FOOD_NAMES),
    )
    await state.set_state(OrderFood.choosing_food_name)


@router.message(OrderFood.choosing_food_name, F.text.in_(FOOD_NAMES))
async def food_chosen(message: Message, state: FSMContext):
    await state.update_data(chosen_food=message.text.lower())
    await message.answer(
        text="Thanks. Now, please, choose a size of portion:",
        reply_markup=make_row_keyboard(FOOD_SIZES),
    )
    await state.set_state(OrderFood.choosing_food_size)


@router.message(OrderFood.choosing_food_name)
async def food_chosen_incorrectly(message: Message):
    await message.answer(
        text="I don't know such a dish.\n\n"
        "Please, choose from a list above:",
        reply_markup=make_row_keyboard(FOOD_NAMES),
    )


@router.message(OrderFood.choosing_food_size, F.text.in_(FOOD_SIZES))
async def food_size_chosen(message: Message, state: FSMContext):
    user_data = await state.get_data()
    await message.answer(
        text=f"You have chose {message.text.lower()} portion {user_data['chosen_food']}.\n",
        reply_markup=ReplyKeyboardRemove(),
    )
    await state.clear()

How to cancel any state?

Add such a command:

@router.message(Command(commands=["cancel"]))
@router.message(F.text.lower() == "cancel")
async def cmd_cancel(message: Message, state: FSMContext):
    await state.clear()
    await message.answer(
        text="Action is canceled",
        reply_markup=ReplyKeyboardRemove()
    )

Different strategies of FSM:

  • USER_IN_CHAT is the default strategy. The state and data are different for each user in each chat. That is, the user will have different states and data in other groups, as well as in the DM with the bot.
  • CHAT - state, and data are common to the entire chat. In the DM the difference is unnoticeable, but in the group, all participants will have the same state and common data.
  • GLOBAL_USER - In all chats the same user will have the same state and data.
  • USER_IN_TOPIC - A user can have different states depending on the topic in the supergroup-forum.

To set up the strategy you need the following code:

from aiogram.fsm.strategy import FSMStrategy

async def main():
    dp = Dispatcher(storage=MemoryStorage(), fsm_strategy=FSMStrategy.CHAT)
Clone this wiki locally