Обучение #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