Не сохраняются данные в FSM Aiogram
Пишу телеграм бот на aiogram.
Eсть FSM которая записывает 2 состояния.
Есть колбек хэндлер, в котором нужно реализовать проверку состояний которые записал выше FSM.
Как это можно реализовать?
Вот здесь загрузил часть кода с этими FSM и нужным колбэком.
Почему-то он не понимает, что находится в data после записи в FSM
class Form(StatesGroup):
firstname = State()
lastname = State()
reg_state_open = State()
reg_state_closed = State()
# Close reg now button
@dp.callback_query_handler(text_contains = 'close_now')
async def close_now(message: types.CallbackQuery):
if message.data == 'close_now':
await bot.send_message(chat_id=message.message.chat.id, text='Введите 1, чтобы закрыть дальнейшую регистрацию.')
await Form.reg_state_closed.set() # Далее вводим 1
await message.answer()
@dp.message_handler(state=Form.reg_state_closed)
async def reg_state_open(message: types.Message, state: FSMContext):
async with state.proxy() as data1:
data1['reg_state1'] = int(message.text) # сохраняю состояние 1 в data1['reg_state1']
await message.answer(text='Регистрация успешно отключена 1')
print('1:', data1['reg_state1'])
await state.finish()
# Open reg now button
@dp.callback_query_handler(text_contains = 'open_now')
async def close_now(message: types.CallbackQuery):
if message.data == 'open_now':
await bot.send_message(chat_id=message.message.chat.id, text='Введите 0, чтобы открыть дальнейшую регистрацию.')
await State.set(Form.reg_state_open) # Далее вводим 0
await message.answer()
@dp.message_handler(state=Form.reg_state_open)
async def reg_state_closed(message: types.Message, state: FSMContext):
async with state.proxy() as data2:
data2['reg_state2'] = int(message.text) # сохраняю состояние 0 в data2['reg_state2]
await message.answer(text='Регистрация включена 0')
print('0:', data2['reg_state2'])
await state.finish()
# как в этом колбекхэндлере проверить записанные выше два состояния (1 и 0). Например, если выше я ввел 0 - выполняется проверка 0 ли в data2['reg_state2], если 0 то дальше можно выполнить регистрацию, если же проверка говорит, что там 1 - регистрация недоступна и этот хэндлер выдает сообщение об этом:
# 'Online registration' button from /start menu
@dp.callback_query_handler(text_contains = 'reg')
async def donate (message: types.CallbackQuery):
if data1['reg_state1'] == 0:
if not db.exists_list(message.message.chat.id): # проверка существования пользователя в БД с помощью функции db.exists_list
await bot.send_message(chat_id=message.message.chat.id, text='Для регистрации введите своё имя.')
await State.set(Form.firstname) # далее вводим имя
await message.answer(text='')
else: # если пользователь существует в БД, то выводим:
await message.answer('Вы уже зарегистрированы')
else: # data2['reg_state2'] == 1 ? (если рега off то выдаем сообщение:)
await message.answer('Регистрация уже отключена.')
await message.answer()
Ответы (1 шт):
Автор решения: oleksandrigo
→ Ссылка
Вам просто нужно сделать некоторые данные не стираемыми всякими finish, reset_state.
Вот так примерно. Код не проверял. По идее должно работать.
import typing
from aiogram import Bot, Dispatcher, executor, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import StatesGroup, State
import config
# теперь все переменные в дате которые начинаются с _ будут нестираемыми
class GMemoryStorage(MemoryStorage):
async def reset_state(self, *,
chat: typing.Union[str, int, None] = None,
user: typing.Union[str, int, None] = None,
with_data: typing.Optional[bool] = True):
await self.set_state(chat=chat, user=user, state=None)
if with_data:
new_data = {}
old_data = await self.get_data(chat=chat, user=user)
for key, value in old_data.items():
if key.startswith("_"):
new_data[key] = value
await self.set_data(chat=chat, user=user, data=new_data)
self._cleanup(chat, user)
bot = Bot(token=config.BOT_TOKEN)
storage = GMemoryStorage()
dp = Dispatcher(bot, storage=storage)
class Form(StatesGroup):
firstname = State()
lastname = State()
reg_state_open = State()
reg_state_closed = State()
# Close reg now button
# почему именно text_contains? У вас же вроде точное сравнение должно быть
# @dp.callback_query_handler(text_contains='close_now')
@dp.callback_query_handler(text='close_now')
async def close_now(call: types.CallbackQuery):
# называйте переменные адекватно, колбек - callback_query/callback/call, сообщение - message/msg
# в идеале делать такой ансвер в начале колбека, чтобы он наверняка сработал
await call.answer()
# зачем второй раз проверка?
# if call.data == 'close_now':
# нет смысла усложнять себе жизнь юзая bot.send_message если
# вы отправляете сообщение в этот же чат
# await bot.send_message(chat_id=call.message.chat.id, text='Введите 1, чтобы закрыть дальнейшую регистрацию.')
await call.message.answer('Введите 1, чтобы закрыть дальнейшую регистрацию.')
await Form.reg_state_closed.set() # Далее вводим 1
@dp.message_handler(state=Form.reg_state_closed)
async def reg_state_open(message: types.Message, state: FSMContext):
# hint: рекомендую сделать проверку, написал ли юзер число
async with state.proxy() as data:
# добавляем _ перед перменной
# вместо int(message.text) делаем просто True
data['_reg_off'] = True
await message.answer('Регистрация успешно отключена 1')
# смысл его сохранять если вы тут же делате finish?
# UPD. теперь смысл есть
await state.finish()
# Open reg now button
@dp.callback_query_handler(text='open_now')
async def close_now(call: types.CallbackQuery):
await call.answer()
# то же самое
# if message.data == 'open_now':
# await bot.send_message(chat_id=message.message.chat.id, text='Введите 0, чтобы открыть дальнейшую регистрацию.')
await call.message.answer('Введите 0, чтобы открыть дальнейшую регистрацию.')
await State.set(Form.reg_state_open) # Далее вводим 0
@dp.message_handler(state=Form.reg_state_open)
async def reg_state_closed(message: types.Message, state: FSMContext):
async with state.proxy() as data:
# если регистрацию не отключали то просто удалим данные из даты
del data['_reg_off']
await message.answer('Регистрация включена')
await state.finish()
# 'Online registration' button from /start menu
@dp.callback_query_handler(text='reg')
async def donate(call: types.CallbackQuery, state: FSMContext):
await call.answer()
async with state.proxy() as data:
# если True то регистрация отключена
if data.get('_reg_off') is True:
await call.answer('Регистрация уже отключена.')
# иначе включена
else:
# проверка существования пользователя в БД с помощью функции db.exists_list
if not db.exists_list(call.message.chat.id):
await call.message.answer('Для регистрации введите своё имя.')
# await bot.send_message(chat_id=call.message.chat.id, text='Для регистрации введите своё имя.')
await State.set(Form.firstname) # далее вводим имя
else: # если пользователь существует в БД, то выводим:
await call.answer('Вы уже зарегистрированы')
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)