Как запросить данные у пользователя в telegram боте (например имя, фамилию) и сохранить в переменную , чтобы потом использовать в других хэндлерах?

Рейтинг: 0Ответов: 1Опубликовано: 06.07.2023

Недавно начал изучать создание телеграм ботов с использованием библиотеки aiogram. И по-началу казалось все понятно, когда бот работает по шаблону: если пользователь написал это - сделать вот это. Но я совершенно не понимаю как можно реализовать шаблон вопроса или запроса и сохранения данных.

Буду от всей души благодарен человеку , который пришлет код бота с использованием aiogram, который: 1.запрашивает имя, сохраняет имя , 2.запрашивает фамилию , сохраняет фамилию, 3.может по команде вывести пользователю введенные им данные(его фамилию и имя)

Ответы

▲ 0Принят

Для временного хранения данных вы можете использовать временную память машины состояний, про которую подробно растолкует человек в этой статье: https://surik00.gitbooks.io/aiogram-lessons/content/chapter3.html

Пример кода для вашего понимания:

from asyncio import Lock

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

bot = Bot(token="<ВАШ_ТОКЕН>", parse_mode='HTML')
dp = Dispatcher(bot=bot, storage=MemoryStorage())

lock = Lock()

# класс для настройки машины состояний
class RegisterMessages(StatesGroup):
    step1 = State()
    step2 = State()


class DB:
    answer_data = {}


@dp.message_handler(commands='start', state=None)
async def start(message: types.Message):
    await RegisterMessages.step1.set()
    await bot.send_message(message.from_user.id, text='Здравствуйте! Введите имя:')


@dp.message_handler(content_types='text', state=RegisterMessages.step1)
async def reg_step1(message: types.Message):
    async with lock:
        DB.answer_data['name'] = message.text
    await bot.send_message(message.from_user.id, text='Принято! Введите фамилию:')
    await RegisterMessages.next()


@dp.message_handler(content_types='text', state=RegisterMessages.step2)
async def reg_step2(message: types.Message, state: FSMContext):
    async with lock:
        DB.answer_data['surname'] = message.text
    await bot.send_message(message.from_user.id, text='Принято! Чтобы посмотреть данные введите команду /check')
    await state.finish()


@dp.message_handler(commands='check')
async def get_reg_data(message: types.Message):
    answer = ''
    answer += f'Имя: {DB.answer_data["name"]}\n\n'
    answer += f'Фамилия: {DB.answer_data["surname"]}'
    await bot.send_message(message.from_user.id, text=answer)


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

В идеале для средних-крупных проектов использовать API с бэкендом или хотя бы БД. В данном коде я использую временную память в виде класса и словаря.

Его так же можно сравнить с тем способом, который предоставляет нам FSMContext.proxy(), который позволяет хранит в себе данные разделяя доступ между пользователями, чтобы никто не перехватил данные другого пользователя. Этот способ подходит, если данные мы передаем во время работы машины состояний.

Но так как данные должны быть выведены после закрытия машины состояний. Мы имитировали блокировку данных для передачи между пользователями и создания путаницы с помощью класса Lock() из библиотеки asyncio.