#4 – SQLite3. Подключение к базе данных

За урок вы выполните подключение базы данных к вашему Телеграм Боту. Вы подключите БД SQLite3, но в будущем по схожему принципу сможете подключать любые другие БД.
Видеоурок
База данных SQLite3 была выбрана в качестве примера по причине ее простоты настройки и использования. В точно таком же формате вы в будущем можете подключиться к любой другой базе данных, что поддерживается языком Python. Это могут быть: MySQL, PostgreSQL, MongoDB и многие другие.
Если ваш сайт работает с MySQL, то вы легко можете скачать коннектор для Питона, установить его через pip и подключиться к вашей БД, что используется на сайте. Далее вы сможете выводить ту же информацию, что выводите на сайте.
В ходе урока был показан общий принцип работы с базами данных. В будущем вы можете использовать любую другую БД на свое усмотрение.
Весь код будет доступен после подписки на проект!
Как вывести определенную запись в sqlite согласно условиям python + Telegram bot
У меня есть телеграм бот. Заранее скажу, что те кто используют моего бота есть в моей базе данных! У меня в боте есть кнопка «Оформить заказ✅» я пытаюсь сделать так, чтобы тот кто нажимал на эту кнопку проверился есть ли он(Его id) в БД и если есть то вывести запись где есть его id (Соответственно у меня кроме id в записи выйдет информация о nickname Имя, Фамилия, телефон и username) Но когда я пытаюсь вывести эту информацию(запись) используя fetchone() то выводится только первая запись по умолчанию и она не реагирует на то, что, кто нажал на кнопку «Оформить заказ✅». А я хотел бы чтобы она выводила запись согласно id человека нажавшего на кнопку «Оформить заказ✅» то есть, если его id есть в БД то вывести запись(id username имя телефон и тп) где есть его id.
@bot.message_handler(content_types=['text']) def handler(message): with sq.connect("bot5.db") as con: cur = con.cursor() chat_id = message.chat.id if message.text == "Оформить заказ✅": exists = cur.execute("SELECT 1 FROM info1 WHERE [chat_id]).fetchone() if exists == True: print("DA") cur.execute(""" SELECT * FROM info1 WHERE chat_id """) data2 = cur.fetchone() print(data2) chat_id = message.chat.id bot.send_message(chat_id, '\n'.join(map(str, data2)))
Фото с моей базы данных
P.S Смог сделать так, думаю проблема в том что я не могу правильно сделать так чтобы выводилась запись(информация) именно того кто нажал на кнопку «Оформить заказ✅» Несмотря на то что, кто нажимает на эту кнопку выводится только первая запись в базе данных! 
Отслеживать
задан 17 окт 2021 в 14:31
25 7 7 бронзовых знаков
прочитайте sqlite3 для совершенных новичков
17 окт 2021 в 16:41
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Вот оно современное поколение бот-девелоперов. Эх.
chat_id = call.message.chat.id if message.text == "Оформить заказ✅": cur.execute(f'SELECT * FROM info1 WHERE ') exists = cur.fetchall() if exists == True: print(exists)
Отслеживать
ответ дан 17 окт 2021 в 16:37
316 1 1 серебряный знак 7 7 бронзовых знаков
Прокачиваем телеграм-бота: пишем полноценный бэкенд
Сегодня мы продолжим этот проект и добавим возможности нашему бэкенду для телеграм-бота. Если хотите разобраться в теме телеграм-ботов с самого начала, почитайте эти статьи:
Логика проекта
Мы сделаем простого бота для приёма отчётов — что сделано за день или над чем идёт работа:
- Сообщение может написать боту кто угодно. Бот запомнит, кто ему написал.
- Бот будет работать только с текстовыми сообщениями. Стикеры и файлы не подойдут.
- Чтобы никто не спамил, бот обрезает сообщение до 500 символов и записывает их в свою базу данных.
- База данных будет настоящая — SQLite, с которой Python работает без дополнительных настроек.
- У бота будут две команды — посмотреть все отчёты за вчера и за сегодня. По этим командам бот присылает отчёты.
- Другие команды бот игнорирует, удалить отчёт нельзя, бот помнит всё.
Это простая, но рабочая логика бэкенда — с ним бот уже может приносить пользу и быть рабочим инструментом.
Что понадобится
Для скрипта нам понадобится Python — половина современного бэкенда пишется именно на нём.
Также мы будем использовать базу данных SQLite — она простая, быстрая и работает практически везде. Прочитайте о ней: SQLite — самая простая база данных, которая работает везде
Код обработки команд для бота мы возьмём из наших прошлых статей про Телеграм и адаптируем под новый проект:
Исходный код прошлого проекта
# подключаем модуль для Телеграма import telebot # указываем токен для доступа к боту bot = telebot.TeleBot(123456789:AAAAA12345678abcdef12345678abcdef') # приветственный текст start_txt = 'Привет! Это журнал «Код». \n\nТеперь у бота появился бэкенд.' # обрабатываем старт бота @bot.message_handler(commands=['start']) def start(message): # выводим приветственное сообщение bot.send_message(message.from_user.id, start_txt, parse_mode='Markdown') # запускаем бота if __name__ == '__main__': while True: # в бесконечном цикле постоянно опрашиваем бота — есть ли новые сообщения try: bot.polling(none_stop=True, interval=0) # если возникла ошибка — сообщаем про исключение и продолжаем работу except Exception as e: print('❌❌❌❌❌ Сработало исключение! ❌❌❌❌❌')
Подключаем базу данных
Мы будем хранить все отчёты пользователей в базе данных — это позволит нам хранить почти неограниченное количество отчётов и быстро находить среди них нужные. Для этого сначала подключим библиотеку sqlite3:
# модуль для работы с базой данных
import sqlite3 as sl
После этого можем подключиться к файлу базы — это обычный файл, который будет храниться в той же папке, что и скрипт:
# подключаемся к файлу с базой данных
con = sl.connect(‘reports.db’)
А вот тут есть тонкий момент: если это наш первый запуск программы, то после подключения скрипт получит пустую базу, без таблиц и внутренней структуры. Если мы попробуем туда что-то записать, то получим ошибку. Чтобы такого не было, сразу сделаем проверку, есть ли в базе нужная нам таблица. Если есть — всё хорошо, продолжаем работу, а если нет — просто создадим её и тоже продолжим работу.
Обратите внимание на структуру таблицы: чтобы каждая запись имела свой уникальный ключ, мы используем для этого комбинацию даты и времени. Дело в том, что время в Python можно получить с точностью до миллисекунды — этого достаточно для того, чтобы у каждого сообщения было своё уникальное время.
Ещё нам нужно хранить дату, чтобы выбирать по ней отчёты за вчера и за сегодня — сделаем это в поле date. В остальные поля будем записывать id и ник пользователя в Телеграме и сам текст сообщения.
# открываем файл with con: # получаем количество таблиц с нужным нам именем data = con.execute("select count(*) from sqlite_master where type='table' and name='reports'") for row in data: # если таких таблиц нет if row[0] == 0: # создаём таблицу для отчётов with con: con.execute(""" CREATE TABLE reports ( datetime VARCHAR(40) PRIMARY KEY, date VARCHAR(20), id VARCHAR(200), name VARCHAR(200), text VARCHAR(500) ); """)
Запоминаем отчёт пользователя
Когда база готова, мы можем принимать и сохранять все сообщения пользователей. Так как нам нужно каждой записи в таблице дать свой уникальный идентификатор, используем для этого комбинацию даты и времени. Для этого сначала подключим стандартные библиотеки:
# модуль работы со временем
from datetime import datetime, timezone, timedelta
Так как мы считаем каждое сообщение пользователя отчётом о работе, мы будем обрабатывать и запоминать каждое текстовое сообщение в чате. При этом мы принудительно обрежем сообщение и оставим только первые 500 символов, чтобы ограничить возможный спам. Как только скрипт получит любой текст, он занесёт его в базу и отправит пользователю сообщение с подтверждением.
# обрабатываем входящий отчёт пользователя @bot.message_handler(content_types=['text']) def func(message): # подключаемся к базе con = sl.connect('reports.db') # подготавливаем запрос sql = 'INSERT INTO reports (datetime, date, id, name, text) values(?, ?, ?, ?, ?)' # получаем дату и время now = datetime.now(timezone.utc) # и просто дату date = now.date() # формируем данные для запроса data = [ (str(now), str(date), str(message.from_user.id), str(message.from_user.username), str(message.text[:500])) ] # добавляем с помощью запроса данные with con: con.executemany(sql, data) # отправляем пользователю сообщение о том, что отчёт принят bot.send_message(message.from_user.id, 'Принято, спасибо!', parse_mode='Markdown')
Проверим, как работает код: отправим боту любое сообщение и посмотрим, получим ли мы что-то в ответ:

Выводим отчёты за сегодня
В реальном проекте мы бы отдельно прописали ID пользователя, который может запрашивать отчёты, чтобы этой командой мог пользоваться только один человек, например руководитель отдела. Сейчас для наглядности мы сделаем проще: сделаем команду /now доступной для всех. Когда бот её получит, он отправит в ответ все отчёты за сегодня.
Логика поиска и выводов отчёта будет такая:
- Подключаемся к базе.
- Получаем текущую дату и ищем в базе все записи с этой датой.
- Перебираем результаты и формируем из них сообщение с отчётами.
- Отправляем общий отчёт пользователю.
При этом нам ещё нужно предусмотреть ситуацию, когда отчётов сегодня не было. Если этого не сделать, скрипт попытается отправить пустое сообщение и выдаст ошибку. В этом случае нам нужно дополнительно проверить, пустая у нас строка с отчётом или нет. Если пустая — записать в неё текст о том, что за сегодня отчётов не было.
# обрабатываем команду /now @bot.message_handler(commands=['now']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем сегодняшнюю дату now = datetime.now(timezone.utc) date = now.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос к базе data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # перебираем все результаты for row in data: # формируем строку в общем отчёте s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за сегодня if s == '': # формируем новое сообщение s = 'За сегодня ещё нет записей' # отправляем общий отчёт обратно в телеграм bot.send_message(message.from_user.id, s, parse_mode='Markdown')
Перезапускаем скрипт и просим бота показать нам сегодняшние отчёты:

Выводим вчерашние отчёты
Здесь всё то же самое, кроме даты и текста при отсутствии отчётов. С текстом всё просто, а со вчерашней — не совсем. Дело в том, что если штатными средствами получить текущую дату и просто отнять от неё единицу, то скрипт выдаст ошибку. Всё из-за того, что дата — это не целое число, а отдельный объект, из которого нельзя просто вычитать числа.
Чтобы получить вчерашнюю дату, используют функцию timedelta() — она считает разницу между текущей датой и указанным в ней количеством дней и эту разницу хранит как раз в виде объекта, который можно вычитать из даты.
# обрабатываем команду /yesterday @bot.message_handler(commands=['yesterday']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем вчерашнюю дату yesterday = datetime.today() - timedelta(days=1) y_date = yesterday.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # смотрим на результат for row in data: # если результат пустой — ничего не делаем if row[0] == 0: pass # если вчера были какие-то отчёты else: # добавляем их в общий список отчётов s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за вчера if s == '': # формируем новое сообщение s = 'За вчерашний день нет записей' # отправляем пользователю это новое сообщение bot.send_message(message.from_user.id, s, parse_mode='Markdown')
Так как мы только начали работать с ботом, вчерашних сообщений в нём ещё нет, поэтому в ответ на эту команду бот выдаст заготовленный текст:

Результат
Смотрите, что мы сегодня сделали:
- Подключили бэкенд в виде скрипта к фронтенду — телеграм-боту.
- После этого бот смог обрабатывать наши сообщения и команды — запоминать отчёты и отправлять их, когда нужно.
- Мы не трогали фронт, зато все наши изменения в бэкенде приводили к тому, что бот получал новые функции одну за другой.
Так и работает бэкенд: он почти не влияет на интерфейс, зато от него может полностью зависеть логика проекта. Если хотите делать крутой бэкенд и разбираться в этом — приходите в Практикум на курсы бэкенда, там научат всему, что потребуется.
Что нужно доделать в следующий раз
Сейчас бот работает и справляется с задачами, но есть пара моментов, которую нужно будет потом исправить:
- Если отчётов за день станет слишком много, возможно, бот не сможет отправить их в одном сообщении или не сможет отправить в принципе. Нужно добавить проверку на максимальное количество символов, и, если что, — делить одно сообщение на несколько.
- Код вывода сообщений за вчера и за сегодня — одинаковый за исключением нескольких строк. Нужно вынести общую часть в отдельную функцию, чтобы не плодить спагетти-код.
Попробуйте сделать это сами или дождитесь следующей статьи с продолжением, где мы исправим обе эти проблемы.
Готовый код
# подключаем модуль для Телеграма import telebot # модуль работы со временем from datetime import datetime, timezone, timedelta # модуль для работы с базой данных import sqlite3 as sl # указываем токен для доступа к боту bot = telebot.TeleBot('6285051364:AAGG2iZ77NIeWj0YjqIs791qxPhvcS3Yu0s') # приветственный текст start_txt = 'Привет! Это журнал «Код». \n\nТеперь у бота появился бэкенд.' # подключаемся к файлу с базой данных con = sl.connect('reports.db') # открываем файл with con: # получаем количество таблиц с нужным нам именем data = con.execute("select count(*) from sqlite_master where type='table' and name='reports'") for row in data: # если таких таблиц нет if row[0] == 0: # создаём таблицу для отчётов with con: con.execute(""" CREATE TABLE reports ( datetime VARCHAR(40) PRIMARY KEY, date VARCHAR(20), id VARCHAR(200), name VARCHAR(200), text VARCHAR(500) ); """) # обрабатываем старт бота @bot.message_handler(commands=['start']) def start(message): # выводим приветственное сообщение bot.send_message(message.from_user.id, start_txt, parse_mode='Markdown') # обрабатываем команду /now @bot.message_handler(commands=['now']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем сегодняшнюю дату now = datetime.now(timezone.utc) date = now.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос к базе data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # перебираем все результаты for row in data: # формируем строку в общем отчёте s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за сегодня if s == '': # формируем новое сообщение s = 'За сегодня ещё нет записей' # отправляем общий отчёт обратно в телеграм bot.send_message(message.from_user.id, s, parse_mode='Markdown') # обрабатываем команду /yesterday @bot.message_handler(commands=['yesterday']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем вчерашнюю дату yesterday = datetime.today() - timedelta(days=1) y_date = yesterday.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # смотрим на результат for row in data: # если результат пустой — ничего не делаем if row[0] == 0: pass # если вчера были какие-то отчёты else: # добавляем их в общий список отчётов s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за вчера if s == '': # формируем новое сообщение s = 'За вчерашний день нет записей' # отправляем пользователю это новое сообщение bot.send_message(message.from_user.id, s, parse_mode='Markdown') # обрабатываем входящий отчёт пользователя @bot.message_handler(content_types=['text']) def func(message): # подключаемся к базе con = sl.connect('reports.db') # подготавливаем запрос sql = 'INSERT INTO reports (datetime, date, id, name, text) values(?, ?, ?, ?, ?)' # получаем дату и время now = datetime.now(timezone.utc) # и просто дату date = now.date() # формируем данные для запроса data = [ (str(now), str(date), str(message.from_user.id), str(message.from_user.username), str(message.text[:500])) ] # добавляем с помощью запроса данные with con: con.executemany(sql, data) # отправляем пользователю сообщение о том, что отчёт принят bot.send_message(message.from_user.id, 'Принято, спасибо!', parse_mode='Markdown') # запускаем бота if __name__ == '__main__': while True: # в бесконечном цикле постоянно опрашиваем бота — есть ли новые сообщения try: bot.polling(none_stop=True, interval=0) # если возникла ошибка — сообщаем про исключение и продолжаем работу except Exception as e: print('❌❌❌❌❌ Сработало исключение! ❌❌❌❌❌')
Что дальше
Теперь у нас есть полноценный бэкенд для телеграм-бота, который умеет принимать и отправлять отчёты. Но сила бэкенда в том, что его можно обернуть в любой интерфейс, в том числе и в веб-страницу. В следующий раз сделаем именно это: сделаем сайт, на котором будут отображаться все отчёты, которые прислали этому телеграм-боту. Получается, что бэкенд будет один, а фронтенда — два. Магия.
Python Telegram Bot. Как правильно изменить данные в БД Sqlite3?
user = message.from_user.id
sql
val = («balance + 15», user)
c.execute(sql, val)
conn.commit()
При работе в balance он просто записывает значение «balance + 15», вместо прибавления 15 к имеющимся числу
Пробовал делать «небезопасным» методом:
c.execute(«UPDATE main SET balance = balance + 15
WHERE user_id = id_пользователя «)
conn.commit()
В этом случае баланс записывается правильно, но работает только если руками указать id конкретного пользователя
Помогите. люди добрые
- Вопрос задан более трёх лет назад
- 798 просмотров
3 комментария
Средний 3 комментария