Какие изменения произошли в формах aiogram 3?

Как правильно организовать обработку состояний в диспетчере для управления процессом перевода? Учитывая, что у вас есть состояния `waiting_for_username` и `waiting_for_cost`, как вам использовать декоратор для обработки сообщений в каждом из этих состояний без возникновения ошибок?
  • 8 января 2025 г. 14:13
Ответы на вопрос 2
В aiogram 3 произошли некоторые изменения, касающиеся работы с состояниями и диспетчером. В частности, для работы с состояниями теперь используется более удобный способ организации с помощью `FSMContext` и состояния, определяемые через класс, а также изменения в синтаксисе и уровне абстракции.

### Изменения в aiogram 3:

1. **Работа с состояниями:** Теперь состояния определяются как классы, используя `State` и `StatesGroup`.
2. **Декораторы:** Декораторы для обработки состояний изменились. Вместо использования `@dp.message_handler(state=...)`, теперь предпочтительно использовать `@dp.message_handler(F.state...)`, что делает код более читаемым.
3. **Упрощённая работа с контекстом:** Теперь доступ к контексту более упрощён и использует асинхронные функции во многих случаях.

### Пример организации обработки состояний

Для организации обработки сообщений в каждом из состояний можно использовать декораторы, учитывая, что у вас есть два состояния: `waiting_for_username` и `waiting_for_cost`. Можно использовать `StatesGroup`, чтобы определить состояние и обрабатывать сообщения для каждого состояния.

Вот пример кода:

```python
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.utils import executor

# Определяем состояния
class Form(StatesGroup):
    waiting_for_username = State()
    waiting_for_cost = State()

# Инициализация бота и диспетчера
bot = Bot(token='YOUR_TOKEN')
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)

@dp.message_handler(commands='start')
async def cmd_start(message: types.Message):
    await Form.waiting_for_username.set()  # Установка состояния
    await message.reply("Пожалуйста, введите ваше имя пользователя.")

@dp.message_handler(state=Form.waiting_for_username)
async def process_username(message: types.Message, state: FSMContext):
    username = message.text
    await state.update_data(username=username)  # Сохранение данных
    await Form.waiting_for_cost.set()  # Переход к следующему состоянию
    await message.reply("Теперь введите стоимость.")

@dp.message_handler(state=Form.waiting_for_cost)
async def process_cost(message: types.Message, state: FSMContext):
    cost = message.text
    # Здесь можно обработать стоимость
    user_data = await state.get_data()  # Получение данных
    username = user_data.get('username')
    
    await message.reply(f"Спасибо, {username}! Вы указали стоимость: {cost}.")
    await state.finish()  # Завершение состояний

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)
```

В этом коде:

- Мы определяем `StatesGroup`, где задаём состояния `waiting_for_username` и `waiting_for_cost`.
- Используем `await Form.waiting_for_username.set()`, чтобы установить текущее состояние.
- Функции для обработки сообщений в разных состояниях используют `state` для получения и обновления данных.
- Завершаем состояния с помощью `await state.finish()`, когда процесс завершен.

Таким образом, при правильной настройке состояний и обработчиков сообщений вы можете избежать ошибок и плавно управлять процессом перевода.
Ну прям в ошибке написано, что надо удалить state, при передаче агрумента (в аиограм 3 не поддерживается передача именованных аргументов, в обработчик сообщений). Надо так: 
@dp.message(transferForm.waiting_for_username)

Ну и к слову, вот это неправильно:
await transferForm.waiting_for_username.set()  # Устанавливаем состояние ожидания username

Состояние устанавливать надо так:
await state.set_state( transferForm.waiting_for_username)
Похожие вопросы