Вопрос или проблема
Я хочу сделать аналог register_next_step_handler из telebot для aiogram. Как я уже понял, мне нужно использовать FSM для этого. Однако я не могу понять, что мне делать с этим примером:
@bot.message_handler(func=lambda message: message.text == "🚫 Запретить публикацию на время")
def prohibit_sending_messages_button(message):
msg = bot.send_message(message.chat.id, "Введите время блокировки в минутах (0 для отмены; умножьте на 60/1440, чтобы указать часы/дни):")
bot.register_next_step_handler(msg, block_sending_for_minutes)
def block_sending_for_minutes(message):
global acceptable_time
# Измените значение acceptable_time на текущее время + выбранное время (может быть математическое выражение)
acceptable_time = message.date + eval(message.text) * 60
bot.send_message(message.chat.id, f"Запрет на отправку сообщений будет действовать до {datetime.fromtimestamp(acceptable_time).strftime('%H:%M:%S %d/%m/%Y')}")
Я пытаюсь сделать это:
@router.message(is_admin & F.text == "🚫 Запретить публикацию на время")
async def prohibit_sending_messages_button(message: Message, state: FSMContext) -> None:
await state.set_state(Form.blocking_time)
await message.answer("Введите время блокировки в минутах (0 для отмены; умножьте на 60/1440, чтобы указать часы/дни):")
@router.message(Form.blocking_time)
async def block_sending_for_minutes(message: Message) -> None:
global acceptable_time
# Измените значение acceptable_time на текущее время + выбранное время (может быть математическое выражение)
acceptable_time = message.date + eval(await message.text) * 60
await message.answer(f"Запрет на отправку сообщений будет действовать до {datetime.fromtimestamp(acceptable_time).strftime('%H:%M:%S %d/%m/%Y')}")
Мои вопросы:
- Нужно ли создавать отдельный класс для этого, если да, то следует ли помещать все классы FSM в отдельный файл и каково правильное название для класса и самой переменной?
- Нужно ли использовать state.clear(), если да, то как мне получить state, если нет, то получается, что я просто больше не использую этот класс?
Ответ или решение
Для того чтобы корректно использовать состояние конечного автомата (FSM) в библиотеке aiogram для регистрации обработчика следующего сообщения, а именно для реализации логики аналогичной register_next_step_handler
из telebot, давайте детально разберем ваш вопрос и предложим правильное решение.
Пример использования FSM в aiogram
-
Создание класса состояний
В aiogram FSM реализация осуществляется с помощью классов, которые содержат состояния. Вы можете создать класс состояний в отдельном файле или же в том же файле, где у вас написаны обработчики.
Пример класса:
from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup class Form(StatesGroup): blocking_time = State()
-
Регистрация обработчиков
Используя состояние, вы можете зарегистрировать обработчики сообщений. Первый обработчик будет запрашивать у пользователя ввод времени блокировки, а второй обработчик будет обрабатывать этот ввод.
Пример кода с учетом ваших требований:
from aiogram import Bot, Dispatcher, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.dispatcher import FSMContext, Dispatcher from aiogram.dispatcher.filters import State from aiogram.utils import executor from datetime import datetime bot = Bot(token='YOUR_BOT_TOKEN') dp = Dispatcher(bot, storage=MemoryStorage()) class Form(StatesGroup): blocking_time = State() @dp.message_handler(lambda message: message.text == "🚫 Prohibit publication for a while") async def prohibit_sending_messages_button(message: types.Message, state: FSMContext) -> None: await Form.blocking_time.set() await message.answer("Введите время блокировки в минутах (0 для отмены; умножьте на 60/1440 для часов/дней):") @dp.message_handler(state=Form.blocking_time) async def block_sending_for_minutes(message: types.Message, state: FSMContext) -> None: global acceptable_time try: blocking_duration = int(message.text) acceptable_time = message.date.timestamp() + blocking_duration * 60 await message.answer(f"Запрет на отправку сообщений будет действовать до {datetime.fromtimestamp(acceptable_time).strftime('%H:%M:%S %d/%m/%Y')}") except ValueError: await message.answer("Пожалуйста, введите корректное число минут.") await state.finish() # Завершаем текущее состояние
Ответы на ваши вопросы:
-
Необходимость создания отдельного класса для состояний
Да, создание класса для состояний является необходимым шагом для работы с FSM в aiogram. Все классы FSM можно разместить в отдельном файле, чтобы поддерживать чистоту кода и модульность. Примерное имя для класса —
Form
, а переменная состояния может называтьсяblocking_time
. -
Использование
state.clear()
Функция
state.finish()
завершает текущее состояние, и вы можете использовать ее в конце вашего обработчика. Очистка состояния (например, с помощьюstate.clear()
) не является обязательной, если состояние завершается корректно. Тем не менее, если вы предполагаете, что бот может остаться в состоянии после частичного выполнения логики, вам следует явно очистить состояние, чтобы избежать конфликтов в будущем.
Завершение
Таким образом, в aiogram вы можете легко создать FSM для обработки последовательных сообщений от пользователя. Используйте классы состояний, корректно обрабатывайте входные данные и не забывайте очищать состояние после завершения процесса.