Обучение #3
Хай, я получил от людей проблему с установкой программы для базы данных, из 1 урока, так вот, если у вас после установки нет программы как на скриншоте:
Её можно скачать по ссылке - *КЛИКАБЕЛЬНО*
При установке, выбираем Modify
Вроде разобрались (если не помогло прошу написать мне в личные сообщения: @Xacker_Name_new
-------------------------------------------------------------------------
Давайте начнём работать с базой данных, с помощью вспомогательного класса work_db из файла class_db.py мы будем записывать все анкеты в базу данных.
Возьмём код бота из Урока #2
from aiogram.dispatcher.filters.state import State, StatesGroup from aiogram import Bot, Dispatcher, executor, types from aiogram.dispatcher import FSMContext from aiogram.types import ReplyKeyboardRemove from class_db import work_db #Импорируем класс для работы с базой данных из файла class_db.py import test as bb #Импортируем файл test.py в переменную bb (мне так удобнее работать с ним) import config as c #Импортируем файл config.py в переменную с (опять же мне так удобнее) #Создаём класс бота и дистпетчера bot = Bot(token=c.token) #Берём токен бота из файла config.py который импортировали ранее в переменную c dp = Dispatcher(bot) db_work = work_db(c.host, c.port, c.user, c.password, c.database) #Создаём экземпляр класса для работы с базой данных, передав все нужные параметры из конфига class anketa(StatesGroup): name = State() floor = State() age = State() @dp.message_handler(content_types=['text']) #Обрабатываем каждое сообщение от пользователей, добавляем content_types для обработки текста, в будущих уроках будет фото и видео async def text(message: types.Message): #Асинхронная функция с название "text" которая принимает в переменную message, текст пользователя отправевшего сообщение if message.text == '/start': await bot.send_message(message.chat.id, 'Привет, заполни анкету, или посмотри информацйию о мне', reply_markup=bb.mark_menu) #Обрабатываем команду /start и выводим клавиатуру из файлы test.py elif message.text == 'Информация': await bot.send_message(message.chat.id, f'Сюда пишем какую либо информацию, например я хочу вывести ID пользователя\nТвой ID: {message.chat.id}') elif message.text == 'Заполнить анкету': await bot.send_message(message.chat.id, 'Введите своё имя:') await anketa.name.set() @dp.message_handler(state=anketa.name) async def anketa_name(message: types.Message, state: FSMContext): #Как видите у нас добавился FSMContext, он нам нужен как раз для обработки машины состояния #Записываем имя в кеш await state.update_data(name=name) #Далее просим ввести пол, с выбором пола из кнопок await bot.send_message(message.chat.id, 'Выберите свой пол:', reply_markup=bb.main_floor) #добавляем вывод кнопок с выбором пола await anketa.floor.set() @dp.message_handler(state=anketa.floor) async def anketa_name(message: types.Message, state: FSMContext): #Записываем пол в кеш await state.update_data(floor=floor) #Далее просим ввести свой возраст await bot.send_message(message.chat.id, 'Выберите свой пол:', reply_markup=ReplyKeyboardRemove()) #убираем текстовую клавиатуру await anketa.age.set() @dp.message_handler(state=anketa.age) async def anketa_name(message: types.Message, state: FSMContext): #Получим все данные записанные в кеш data = await state.get_data() #Сортируем их по переменным name = data['name'] #В ковычках пишем name, потому что сами записывали в такую переменную, там может быть любая другая floor = data['floor'] #В ковычках пишем floor, потому что сами записывали в такую переменную, там может быть любая другая age = message.text #записываем ввод пользователя в переменную age await state.finish() #Завершаем работу с машиной состояний #Выведем анкету пользователю await bot.send_message(message.chat.id, f'Ваша анкета:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}\n\nСпасибо за уделение времени', reply_markup=bb.mark_menu) #Отправляем анкету, благодарим, и выдаём ему текстовоем меню #Отправим анкету администратору по его ID из config.py #Так же выведем ID пользователя и его юзернейм await bot.send_message(c.admin, f'Пользователь: {message.chat.id}\n@{message.from_user.username} заполнил анкету\nЕго данные:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}') if __name__ == "__main__": #Если скрипт запущен с этого файла, запускаем executor executor.start_polling(dp, skip_updates=True) #skip_updates=True - нужен для того чтобы не обрабатывать сообщения которые были присланы пользователем в тот момент когда бот был выключен
Для начала давайте создадим функцию которая будет создавать таблицы:
def creat_table(): #Данную функцию будем запускать при каждом запуске кода, параметры функция не принимает #Для начала конектимся к базе данных: connection = db_work.connect_db() if connection: #Если класс вернул конект, а не False #Напишем сам запрос creat_table_request = 'CREATE TABLE IF NOT EXISTS `ankets`(id int AUTO_INCREMENT, name varchar(32), floor varchar(10), age int, PRIMARY KEY (id));' #И так мы написали запрос, но для чего он нам? #Он нам для того что-бы создать таблицу для анкет где будут следующие данные: id - это будет id анкеты (число), оно будет прописываться само (из-за AUTO_INCREMENT) #name типа сроки длинной не более 32 символов, floor типа строки не более 10 символов и age типа числа без ограничения #Первичный ключ (PRIMARY KEY) — особенное поле в таблице, которое позволяет однозначно идентифицировать каждую запись в ней #Запрос написан, давайте его выполним: status = db_work.create_table(connection, creat_table_request) #Предаём необходимые данные (Конект и сам запрос) #Проверяем статус создания базы данных: if status: #Если вернуло True значит всё хорошо (выведем в консоль что запрос выполнен) print('Таблица успешно создана') #Закрываем конект if db_work.connect_close(connection): print('Конект закрыт!') else: #Если нам вернуло False, значит произошла ошибка, в вспомогательном классе мы прописали вывод ошибки print('Ошибка указана выше') else: #Если вернуло False, значит не удалось создать таблицу, ошибку мы так же вывели в классе print('Ошибка указана выше') else: #Если мы не смогли подключиться к базе данных, то опять же ошибка была выведена в классе print('Ошибка указана выше')
И так давайте допишем запуск этой функции:
if __name__ == "__main__": #Если скрипт запущен с этого файла, запускаем executor creat_table() #Запускаем функцию создания таблицы executor.start_polling(dp, skip_updates=True) #skip_updates=True - нужен для того чтобы не обрабатывать сообщения которые были присланы пользователем в тот момент когда бот был выключен
У меня возникла ошибка с вспомогательным классом для работы с базой данных, текст ошибки:
Traceback (most recent call last): File "C:\Users\ffff1\OneDrive\Рабочий стол\bot_ankets\main.py", line 14, in <module> db_work = work_db(c.host, c.port, c.user, c.password, c.database) #Создаём экземпляр класса для работы с базой данных, передав все нужные параметры из конфига ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: work_db.__init__() takes 1 positional argument but 6 were given
Это из-за того что я не написал в функции "__init__" принятие нескольких аргументов, а передаю аж 6, поэтому давайте перепишем функцию "__init__":
def __init__(self, host, port, user, password, database): #Функция для иницилизирования переменных в класс, запускать её не надо self.host = host self.port = port self.user = user self.password = password self.database = database
...Пишет что базы нет, в таком случае в программе Workbench 8.0 CE заходим в базу которые создали в первом уроке
В строке (указанной прямоугольником пишем следующие:
Далее нажимаем на молнию (указана стрелочкой)
Красная стрелочка: нам пишет что база данных создана!
Черная стрелочка: На том месте нажимаем правой кнопкой и Refresh (У нас появляется база данных)
Далее покажу как смотреть данные из неё...
Таблица успешно создана, и конект успешно закрыт, я считаю это успех)
Давайте напишем функцию которая будет записывать данные в таблицу:
def insert_table(name_, floor_, age_): #Данная функция принимает имя таблицы в которую надо записать данные (Сразу скажу т.к. мы записывать будет в ankets ропишем получение данных) #Для начала конектимся к базе данных: connection = db_work.connect_db() if connection: #Если класс вернул конект, а не False #Напишем сам запрос insert_table_request = 'INSERT INTO ankets (name, floor, age) VALUES (%s, %s, %s);' #И так в этом запросе мы создаём запись данных with connection.cursor() as cursor: cursor.execute(insert_table_request, (name_, floor_, age_)) #Записываем данные полученные в функцию connection.commit() #Сохраняем изменения print('Данные записаны!') if db_work.connect_close(connection): print('Конект закрыт!') else: #Если нам вернуло False, значит произошла ошибка, в вспомогательном классе мы прописали вывод ошибки print('Ошибка указана выше') else: #Если мы не смогли подключиться к базе данных, то опять же ошибка была выведена в классе print('Ошибка указана выше')
Функция записана, давайте её добавим вызов функции из обработчика возраста:
@dp.message_handler(state=anketa.age) async def anketa_name(message: types.Message, state: FSMContext): #Получим все данные записанные в кеш data = await state.get_data() #Сортируем их по переменным name = data['name'] #В ковычках пишем name, потому что сами записывали в такую переменную, там может быть любая другая floor = data['floor'] #В ковычках пишем floor, потому что сами записывали в такую переменную, там может быть любая другая age = message.text #записываем ввод пользователя в переменную age await state.finish() #Завершаем работу с машиной состояний #Выведем анкету пользователю await bot.send_message(message.chat.id, f'Ваша анкета:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}\n\nСпасибо за уделение времени', reply_markup=bb.mark_menu) #Отправляем анкету, благодарим, и выдаём ему текстовоем меню #Отправим анкету администратору по его ID из config.py #Так же выведем ID пользователя и его юзернейм await bot.send_message(c.admin, f'Пользователь: {message.chat.id}\n@{message.from_user.username} заполнил анкету\nЕго данные:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}') insert_table(name, floor, age) #Передаём необходимые данные
Перезапускаем бота, и заполняем анкету:
FSMStorageWarning: You haven’t set any storage yet so no states and no data will be saved. You can connect MemoryStorage for debug purposes or non-essential data.
Нужно добавить ещё 1 импорт в файл main.py:
from aiogram.contrib.fsm_storage.memory import MemoryStorage
Так же поменяем класс бота и диспетчера:
bot = Bot(token=c.token, parse_mode=types.ParseMode.HTML) dp = Dispatcher(bot, storage=MemoryStorage())
Ещё я допустил ошибку в 2х обработчиках:
@dp.message_handler(state=anketa.name) async def anketa_name(message: types.Message, state: FSMContext): #Как видите у нас добавился FSMContext, он нам нужен как раз для обработки машины состояния #Записываем имя в кеш await state.update_data(name=message.text) #Далее просим ввести пол, с выбором пола из кнопок await bot.send_message(message.chat.id, 'Выберите свой пол:', reply_markup=bb.main_floor) #добавляем вывод кнопок с выбором пола await anketa.floor.set() @dp.message_handler(state=anketa.floor) async def anketa_name(message: types.Message, state: FSMContext): #Записываем пол в кеш await state.update_data(floor=message.text) #Далее просим ввести свой возраст await bot.send_message(message.chat.id, 'Выберите свой пол:', reply_markup=ReplyKeyboardRemove()) #убираем текстовую клавиатуру await anketa.age.set()
Не думайте что я не мастер своего дела, по мимо уроков я ещё и работаю, учусь, и иногда бывают такие ошибки...
Давайте продолжим, запускаем бота и заполняем анкету:
И так мы успешно записали данные, давайте посмотрим их
Заходим двойным щелчком ЛКМ по базе "test_basa"
При наведении на таблице ankets у нас появляются кнопочки, нам нужна эта:
Нажимаем и снизу у нас есть все данные записанные в таблицу:
Молодцы, теперь давайте по команду в бота "/info_table"
Давайте перепишем функцию в вспомогательном классе:
def info_table(self, connection, info, values): #Функция для получения данных из таблицы, в info будем передавать текст запроса try: with connection.cursor() as cursor: cursor.execute(info, values) return cursor.fetchall()[0] #Возвращаем всё что нашли except Exception as eror: print(eror) #Если произошла ошибка, выводим её в консоль return False #Если произошла ошибка, возвращаем False
Выведем все данные по ID 1
Напишем обработчик команды "/info_table":
@dp.message_handler(content_types=['text']) #Обрабатываем каждое сообщение от пользователей, добавляем content_types для обработки текста, в будущих уроках будет фото и видео async def text(message: types.Message): #Асинхронная функция с название "text" которая принимает в переменную message, текст пользователя отправевшего сообщение if message.text == '/start': await bot.send_message(message.chat.id, 'Привет, заполни анкету, или посмотри информацйию о мне', reply_markup=bb.mark_menu) #Обрабатываем команду /start и выводим клавиатуру из файлы test.py elif message.text == 'Информация': await bot.send_message(message.chat.id, f'Сюда пишем какую либо информацию, например я хочу вывести ID пользователя\nТвой ID: {message.chat.id}') elif message.text == 'Заполнить анкету': await bot.send_message(message.chat.id, 'Введите своё имя:') await anketa.name.set() elif message.text == '/info_table': info_request = 'SELECT * FROM ankets WHERE id = %s' values = (1,) connection = db_work.connect_db() #Конектимся к базе данных if connection: #Если конект успешный info = db_work.info_table(connection, info_request, values) if info: #Если получили данные по id = 1 await bot.send_message(message.chat.id, f'Полученные данные: {info}') else: #Если не смогли получить данные await bot.send_message(message.chat.id, 'Не удалось получить данные') else: #Если конект не удался await bot.send_message(message.chat.id, 'Не удалось подключиться к базе данных')
У нас получился такой код, перезапускаем бота, и проверяем работоспособность команды:
Работает отлично, но выводит данные не особо красиво, давайте исправим:
@dp.message_handler(content_types=['text']) #Обрабатываем каждое сообщение от пользователей, добавляем content_types для обработки текста, в будущих уроках будет фото и видео async def text(message: types.Message): #Асинхронная функция с название "text" которая принимает в переменную message, текст пользователя отправевшего сообщение if message.text == '/start': await bot.send_message(message.chat.id, 'Привет, заполни анкету, или посмотри информацйию о мне', reply_markup=bb.mark_menu) #Обрабатываем команду /start и выводим клавиатуру из файлы test.py elif message.text == 'Информация': await bot.send_message(message.chat.id, f'Сюда пишем какую либо информацию, например я хочу вывести ID пользователя\nТвой ID: {message.chat.id}') elif message.text == 'Заполнить анкету': await bot.send_message(message.chat.id, 'Введите своё имя:') await anketa.name.set() elif message.text == '/info_table': info_request = 'SELECT * FROM ankets WHERE id = %s' values = (1,) connection = db_work.connect_db() #Конектимся к базе данных if connection: #Если конект успешный info = db_work.info_table(connection, info_request, values) if info: #Если получили данные по id = 1 await bot.send_message(message.chat.id, f'Полученные данные:\nID: {info["id"]}\nИмя: {info["name"]}\nПол: {info["floor"]}\nВозраст: {info["age"]}') else: #Если не смогли получить данные await bot.send_message(message.chat.id, 'Не удалось получить данные') else: #Если конект не удался await bot.send_message(message.chat.id, 'Не удалось подключиться к базе данных')
Проверяем вывод, и наслаждаемся красотой:
Давайте обновим возраст с помощью инлайн кнопок?
Создаём обработчик команды "/new_value"
Но перед этим напишем класс для ввода ID записи в базе данных:
class new_values(StatesGroup): new_value = State()
И так продолжим писать обработчик:
@dp.message_handler(content_types=['text']) #Обрабатываем каждое сообщение от пользователей, добавляем content_types для обработки текста, в будущих уроках будет фото и видео async def text(message: types.Message): #Асинхронная функция с название "text" которая принимает в переменную message, текст пользователя отправевшего сообщение if message.text == '/start': await bot.send_message(message.chat.id, 'Привет, заполни анкету, или посмотри информацйию о мне', reply_markup=bb.mark_menu) #Обрабатываем команду /start и выводим клавиатуру из файлы test.py elif message.text == 'Информация': await bot.send_message(message.chat.id, f'Сюда пишем какую либо информацию, например я хочу вывести ID пользователя\nТвой ID: {message.chat.id}') elif message.text == 'Заполнить анкету': await bot.send_message(message.chat.id, 'Введите своё имя:') await anketa.name.set() elif message.text == '/info_table': info_request = 'SELECT * FROM ankets WHERE id = %s' values = (1,) connection = db_work.connect_db() #Конектимся к базе данных if connection: #Если конект успешный info = db_work.info_table(connection, info_request, values) if info: #Если получили данные по id = 1 await bot.send_message(message.chat.id, f'Полученные данные:\nID: {info["id"]}\nИмя: {info["name"]}\nПол: {info["floor"]}\nВозраст: {info["age"]}') else: #Если не смогли получить данные await bot.send_message(message.chat.id, 'Не удалось получить данные') else: #Если конект не удался await bot.send_message(message.chat.id, 'Не удалось подключиться к базе данных') elif message.text == '/new_value': await bot.send_message(message.chat.id, 'Введите ID для изменения возраста:') await new_values.new_value.set()
Пишем обработчик ввода пользователя:
@dp.message_handler(state=new_values.new_value) async def anketa_name(message: types.Message, state: FSMContext): #Как видите у нас добавился FSMContext, он нам нужен как раз для обработки машины состояния #Записываем ID в кеш await state.update_data(id_value=message.text) #Выводим инлайн кнопки с числами #Пока напишу прямо тут, в следующих уроках будем создавать функции await bot.send_message(message.chat.id, 'Выберите новое значение:', reply_markup=InlineKeyboardMarkup(row_width=3).add( InlineKeyboardButton(text='1', callback_data='new_value_1'),InlineKeyboardButton(text='2', callback_data='new_value_2'), InlineKeyboardButton(text='10', callback_data='new_value_10'), InlineKeyboardButton(text='25', callback_data='new_value_25'))) #Этого достаточно
from aiogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton
Давайте ещё перепишем функцию в вспомогательном классе:
def edit_table(self, connection, edit, values): #Функция для редактирования данных в таблице, в edit будем передавать текст запроса try: with connection.cursor() as cursor: cursor.execute(edit, values) connection.commit() return True except Exception as eror: print(eror) #Если произошла ошибка, выводим её в консоль return False #Если произошла ошибка, возвращаем False
Теперь перейдём к обработчику нажатий на инлайн кнопки:
@dp.callback_query_handler(lambda call: True, state='*') #Обрабатываем нажатия всех инлайн кнопок, даже когда активно ожидание ввода от пользователя async def callback_inline(call, state: FSMContext): #В переменную call принимаем данные о нажатой кнопке try: #Обрабатываем ошибки, если всё успешно то мы получим переменную id_value на всю функцию data = await state.get_data() id_value = data['id_value'] await state.finish() except Exception as eror: #Если будут ошибки мы их пришлём пользователю await bot.send_message(call.message.chat.id, f'Произошла ошибка: {eror}') return #Останавливаем выполнение функции #Приступим к обработке нажатия кнопок, т.к. у нас записано новое чило в callback_data, но начало одно и тоже #Нам нужно проверять есть ли в нажатой кнопке начало: if 'new_value_' in call.data: #В call.data содержиться callback_data new_value = int(call.data.replace('new_value_', '')) #С момощью этого кода мы получим число типа int, удалив из call.data не нужное нам #Грубыми словами с помощью replace мы заменяем new_value_ на ничего #Теперь давайте заменим значение в таблице по ID которое вписали изначально #Конектимся к базе данных: connection = db_work.connect_db() if connection: #Если конект успешен #Возпользуемся функцией edit_table из вспомогательного класса: new_value_request = 'UPDATE ankets SET age = %s WHERE id = %s' values = (new_value, int(id_value)) status = db_work.edit_table(connection, new_value_request, values) if status: #Если успешно обновили данные await bot.send_message(call.message.chat.id, f'Данные для строки с ID: {id_value}\nУспешно обновлены на: {new_value}') else: #Если произошла ошибка await bot.send_message(call.message.chat.id, 'Произошла ошибка, она отобразилась в консоли!') else: #Если не удалось подключиться к базе данных await bot.send_message(call.message.chat.id, 'Не удалось подключиться к базе данных!')
Запустим бота и проверим работоспособность:
Всё работает, кайф, давайте проверим данные через программу
Для обновления, нажимаем на кнопку:
И так, данные успешно обновлены:
На этом я предлагаю закончить наш урок)
Итоговый код который у нас полчиться:
from aiogram.dispatcher.filters.state import State, StatesGroup from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram import Bot, Dispatcher, executor, types from aiogram.dispatcher import FSMContext from aiogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton from class_db import work_db #Импорируем класс для работы с базой данных из файла class_db.py import test as bb #Импортируем файл test.py в переменную bb (мне так удобнее работать с ним) import config as c #Импортируем файл config.py в переменную с (опять же мне так удобнее) #Создаём класс бота и дистпетчера bot = Bot(token=c.token, parse_mode=types.ParseMode.HTML) #Берём токен бота из файла config.py который импортировали ранее в переменную c dp = Dispatcher(bot, storage=MemoryStorage()) db_work = work_db(c.host, c.port, c.user, c.password, c.database) #Создаём экземпляр класса для работы с базой данных, передав все нужные параметры из конфига class anketa(StatesGroup): name = State() floor = State() age = State() class new_values(StatesGroup): new_value = State() def creat_table(): #Данную функцию будем запускать при каждом запуске кода, параметры функция не принимает #Для начала конектимся к базе данных: connection = db_work.connect_db() if connection: #Если класс вернул конект, а не False #Напишем сам запрос creat_table_request = 'CREATE TABLE IF NOT EXISTS `ankets`(id int AUTO_INCREMENT, name varchar(32), floor varchar(10), age int, PRIMARY KEY (id));' #И так мы написали запрос, но для чего он нам? #Он нам для того что-бы создать таблицу для анкет где будут следующие данные: id - это будет id анкеты (число), оно будет прописываться само (из-за AUTO_INCREMENT) #name типа сроки длинной не более 32 символов, floor типа строки не более 10 символов и age типа числа без ограничения #Первичный ключ (PRIMARY KEY) — особенное поле в таблице, которое позволяет однозначно идентифицировать каждую запись в ней #Запрос написан, давайте его выполним: status = db_work.create_table(connection, creat_table_request) #Предаём необходимые данные (Конект и сам запрос) #Проверяем статус создания базы данных: if status: #Если вернуло True значит всё хорошо (выведем в консоль что запрос выполнен) print('Таблица успешно создана') #Закрываем конект if db_work.connect_close(connection): print('Конект закрыт!') else: #Если нам вернуло False, значит произошла ошибка, в вспомогательном классе мы прописали вывод ошибки print('Ошибка указана выше') else: #Если вернуло False, значит не удалось создать таблицу, ошибку мы так же вывели в классе print('Ошибка указана выше') else: #Если мы не смогли подключиться к базе данных, то опять же ошибка была выведена в классе print('Ошибка указана выше') def insert_table(name_, floor_, age_): #Данная функция принимает имя таблицы в которую надо записать данные (Сразу скажу т.к. мы записывать будет в ankets ропишем получение данных) #Для начала конектимся к базе данных: connection = db_work.connect_db() if connection: #Если класс вернул конект, а не False #Напишем сам запрос insert_table_request = 'INSERT INTO ankets (name, floor, age) VALUES (%s, %s, %s);' #И так в этом запросе мы создаём запись данных with connection.cursor() as cursor: cursor.execute(insert_table_request, (name_, floor_, age_)) #Записываем данные полученные в функцию connection.commit() #Сохраняем изменения print('Данные записаны!') if db_work.connect_close(connection): print('Конект закрыт!') else: #Если нам вернуло False, значит произошла ошибка, в вспомогательном классе мы прописали вывод ошибки print('Ошибка указана выше') else: #Если мы не смогли подключиться к базе данных, то опять же ошибка была выведена в классе print('Ошибка указана выше') @dp.message_handler(content_types=['text']) #Обрабатываем каждое сообщение от пользователей, добавляем content_types для обработки текста, в будущих уроках будет фото и видео async def text(message: types.Message): #Асинхронная функция с название "text" которая принимает в переменную message, текст пользователя отправевшего сообщение if message.text == '/start': await bot.send_message(message.chat.id, 'Привет, заполни анкету, или посмотри информацйию о мне', reply_markup=bb.mark_menu) #Обрабатываем команду /start и выводим клавиатуру из файлы test.py elif message.text == 'Информация': await bot.send_message(message.chat.id, f'Сюда пишем какую либо информацию, например я хочу вывести ID пользователя\nТвой ID: {message.chat.id}') elif message.text == 'Заполнить анкету': await bot.send_message(message.chat.id, 'Введите своё имя:') await anketa.name.set() elif message.text == '/info_table': info_request = 'SELECT * FROM ankets WHERE id = %s' values = (1,) connection = db_work.connect_db() #Конектимся к базе данных if connection: #Если конект успешный info = db_work.info_table(connection, info_request, values) if info: #Если получили данные по id = 1 await bot.send_message(message.chat.id, f'Полученные данные:\nID: {info["id"]}\nИмя: {info["name"]}\nПол: {info["floor"]}\nВозраст: {info["age"]}') else: #Если не смогли получить данные await bot.send_message(message.chat.id, 'Не удалось получить данные') else: #Если конект не удался await bot.send_message(message.chat.id, 'Не удалось подключиться к базе данных') elif message.text == '/new_value': await bot.send_message(message.chat.id, 'Введите ID для изменения возраста:') await new_values.new_value.set() @dp.message_handler(state=new_values.new_value) async def anketa_name(message: types.Message, state: FSMContext): #Как видите у нас добавился FSMContext, он нам нужен как раз для обработки машины состояния #Записываем ID в кеш await state.update_data(id_value=message.text) #Выводим инлайн кнопки с числами #Пока напишу прямо тут, в следующих уроках будем создавать функции await bot.send_message(message.chat.id, 'Выберите новое значение:', reply_markup=InlineKeyboardMarkup(row_width=3).add( InlineKeyboardButton(text='1', callback_data='new_value_1'),InlineKeyboardButton(text='2', callback_data='new_value_2'), InlineKeyboardButton(text='10', callback_data='new_value_10'), InlineKeyboardButton(text='25', callback_data='new_value_25'))) #Этого достаточно @dp.message_handler(state=anketa.name) async def anketa_name(message: types.Message, state: FSMContext): #Как видите у нас добавился FSMContext, он нам нужен как раз для обработки машины состояния #Записываем имя в кеш await state.update_data(name=message.text) #Далее просим ввести пол, с выбором пола из кнопок await bot.send_message(message.chat.id, 'Выберите свой пол:', reply_markup=bb.menu_floor) #добавляем вывод кнопок с выбором пола await anketa.floor.set() @dp.message_handler(state=anketa.floor) async def anketa_name(message: types.Message, state: FSMContext): #Записываем пол в кеш await state.update_data(floor=message.text) #Далее просим ввести свой возраст await bot.send_message(message.chat.id, 'Введите свой возраст:', reply_markup=ReplyKeyboardRemove()) #убираем текстовую клавиатуру await anketa.age.set() @dp.message_handler(state=anketa.age) async def anketa_name(message: types.Message, state: FSMContext): #Получим все данные записанные в кеш data = await state.get_data() #Сортируем их по переменным name = data['name'] #В ковычках пишем name, потому что сами записывали в такую переменную, там может быть любая другая floor = data['floor'] #В ковычках пишем floor, потому что сами записывали в такую переменную, там может быть любая другая age = message.text #записываем ввод пользователя в переменную age await state.finish() #Завершаем работу с машиной состояний #Выведем анкету пользователю await bot.send_message(message.chat.id, f'Ваша анкета:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}\n\nСпасибо за уделение времени', reply_markup=bb.mark_menu) #Отправляем анкету, благодарим, и выдаём ему текстовоем меню #Отправим анкету администратору по его ID из config.py #Так же выведем ID пользователя и его юзернейм await bot.send_message(c.admin, f'Пользователь: {message.chat.id}\n@{message.from_user.username} заполнил анкету\nЕго данные:\n\nИмя: {name}\nПол: {floor}\nВозраст: {age}') insert_table(name, floor, age) #Передаём необходимые данные @dp.callback_query_handler(lambda call: True, state='*') #Обрабатываем нажатия всех инлайн кнопок, даже когда активно ожидание ввода от пользователя async def callback_inline(call, state: FSMContext): #В переменную call принимаем данные о нажатой кнопке try: #Обрабатываем ошибки, если всё успешно то мы получим переменную id_value на всю функцию data = await state.get_data() id_value = data['id_value'] await state.finish() except Exception as eror: #Если будут ошибки мы их пришлём пользователю await bot.send_message(call.message.chat.id, f'Произошла ошибка: {eror}') return #Останавливаем выполнение функции #Приступим к обработке нажатия кнопок, т.к. у нас записано новое чило в callback_data, но начало одно и тоже #Нам нужно проверять есть ли в нажатой кнопке начало: if 'new_value_' in call.data: #В call.data содержиться callback_data new_value = int(call.data.replace('new_value_', '')) #С момощью этого кода мы получим число типа int, удалив из call.data не нужное нам #Грубыми словами с помощью replace мы заменяем new_value_ на ничего #Теперь давайте заменим значение в таблице по ID которое вписали изначально #Конектимся к базе данных: connection = db_work.connect_db() if connection: #Если конект успешен #Возпользуемся функцией edit_table из вспомогательного класса: new_value_request = 'UPDATE ankets SET age = %s WHERE id = %s' values = (new_value, int(id_value)) status = db_work.edit_table(connection, new_value_request, values) if status: #Если успешно обновили данные await bot.send_message(call.message.chat.id, f'Данные для строки с ID: {id_value}\nУспешно обновлены на: {new_value}') else: #Если произошла ошибка await bot.send_message(call.message.chat.id, 'Произошла ошибка, она отобразилась в консоли!') else: #Если не удалось подключиться к базе данных await bot.send_message(call.message.chat.id, 'Не удалось подключиться к базе данных!') if __name__ == "__main__": #Если скрипт запущен с этого файла, запускаем executor creat_table() #Запускаем функцию создания таблицы executor.start_polling(dp, skip_updates=True) #skip_updates=True - нужен для того чтобы не обрабатывать сообщения которые были присланы пользователем в тот момент когда бот был выключен
Я помню что не научил удалять данные с базы данных, но давайте будем честны, вы уже устали делать всё что выше, в следующем задании начнём с удаления данных!
Домашнее задание:
1. Добавить больше кнопок для изменения возраста
2. Создать функцию "creat_table_2" и создать в ней таблицу "users" в которую добавить столбцы:
1. id - как в функции "creat_table"
2. name - типа varchar длинной не более 32 символов
3. password - типа varchar длинной не более 20 символов
4. Возраст - типа int
Записывать в таблицу ничего не надо, просто создать её при запуске бота, как мы это сделали с "creat_table"
В обратной связи жду:
1. Скриншот кода с больший кол-вом кнопок
2. Скриншот кода функции "creat_table_2"
3. Скриншот с программы где видна новая таблица "users" и все столбца в ней
Выполнить ДЗ до 28.09.2023
Спасибо за внимание
С вами был @Xacker_Name_new
Поддержка: @Bsc_Black_Secret_Club_bot