Aiogram3 проблема с работой состояний

Раньше писал на второй версии библиотеки и в боте у меня есть несколько состояний, к примеру создание анкет и их поиск. На второй версии все работало нормально и не было никаких проблем. На третей версии я могу вызывать из состояния обычные команды у которых состояние вовсе не указано и это ломает логику боту. Можно ли как-то обойтись без выдачи всем функциям кастомного состояния?

вот код:

'''

class ProfileCreate(StatesGroup):
    gender = State()
    find_gender = State()
    photo = State()
    name = State()
    age = State()
    city = State()
    desc = State()
    

@router.message(filters.IsFindGender(), ProfileCreate.find_gender)
async def _find_gender(message: types.Message, state: FSMContext, find_gender: str):
    await state.update_data(find_gender=find_gender)
    await message.reply(msg_text.PHOTO, reply_markup=del_kb)
    await state.set_state(ProfileCreate.photo)


@router.message(ProfileCreate.find_gender)
async def _incorrect_find_gender(message: types.Message):
    """Ошибка фильтра гендера"""
    await message.answer(msg_text.INVALID_RESPONSE)
'''

и к примеру я вызываю команду для реферальных ссылок из состояния и она срабатывает, хотя не должна

@router.message(F.text == "✉️")
async def _invite_link_command(message: types.Message, user: Users) -> None:
    """Дает пользователю его реферальную ссылку"""
    bot_user = await bot.get_me()
    await message.answer(msg_text.INVITE_FRIENDS.format(
        user.referral,
        bot_user.username,
        message.from_user.id
        )
    )

если нужно могу отправить более полный код, все по файлам разбито и не очень удобно демострировать


Если что про вариант StateFilter(None) я знаю, но не хотелось бы всем хендлерам прописывать это


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

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

В твоем случае можно написать универсальный обработчик, который будет отлавливать пользователей в состоянии и отвечать на отправку команды определенным сообщением, в зависимости от состояния и шага состояния

@router.message(~StateFilter(None))  # Если пользователь находится в состоянии
async def _state_blocked(message: types.Message, state: FSMContext):
    current_state = await state.get_state()  # Получаем текущее состояние
    if current_state == ProfileCreate.find_gender.state:
        await message.answer("Вы должны выбрать пол перед выполнением других команд.")
    elif current_state == ProfileCreate.photo.state:
        await message.answer("Сначала загрузите фото, прежде чем использовать команды.")
    elif current_state == ProfileCreate.name.state:
        await message.answer("Введите имя, чтобы продолжить.")
    else:
        await message.answer("Вы заполняете анкету. Завершите ее перед выполнением других команд.")
→ Ссылка
Автор решения: Рустам Рысаев

Можно попробовать задать поведение по умолчанию через router.message.filter(), чтобы все хендлеры по умолчанию работали только в состоянии None, а уже у нужных явно указывать StateFilter.

router.message.filter(StateFilter(None))

class ProfileCreate(StatesGroup):
    gender = State()
    find_gender = State()
    photo = State()
    name = State()
    age = State()
    city = State()
    desc = State()

@router.message(filters.IsFindGender(), ProfileCreate.find_gender)
async def _find_gender(message: types.Message, state: FSMContext, find_gender: str):
    await state.update_data(find_gender=find_gender)
    await message.reply(msg_text.PHOTO, reply_markup=del_kb)
    await state.set_state(ProfileCreate.photo)

@router.message(ProfileCreate.find_gender)
async def _incorrect_find_gender(message: types.Message):
    """Ошибка фильтра гендера"""
    await message.answer(msg_text.INVALID_RESPONSE)
→ Ссылка