Онлайн час в Google Meet
Лого на 91. НЕГ „Проф. Константин Гълъбов“

12. клас · Избираем модул · Урок 22

Свързване на Python с база от данни

Програма на Python чете и записва в база от данни: sqlite3 с параметри, справка като DataFrame с pandas и защо слепването на SQL с низове е забранено.

Досега базата беше „отсреща“

В уроци 1–9 пишехте SQL в приложението и в phpMyAdmin — човек пише заявка, човек чете резултата. В модул 4 програмата на C# се свързваше с базата през ADO.NET. Днес правим същото от Python в Colab, защото оттук нататък базата ще е част от програма с AI: в урок 23 моделът ще пише заявката, в урок 24 ще описва резултата ѝ, в урок 25 ще пазим вектори в нея.

Ползваме SQLite — същата база, която стои зад примерите в приложението. Тя е един файл на диска и идва вградена в Python: модулът sqlite3 не иска инсталация, сървър, потребител и парола.

програмаPythonconnect()връзкаexecute(SQL, ?)заявка + параметриfetchall()редове → кортежиuchilishte.dbПри запис: execute(INSERT …) и после commit(), иначе промяната се губи.
Четири стъпки, които ще повтаряте във всяка програма с база.

Пет думи, които стигат

import sqlite3

vrazka = sqlite3.connect("uchilishte.db")   # файлът се създава, ако го няма
cur = vrazka.cursor()

cur.execute("SELECT name, grade FROM students WHERE class_id = ?", (2,))
for ime, uspeh in cur.fetchall():
    print(ime, uspeh)

cur.execute("INSERT INTO classes (id, name) VALUES (?, ?)", (4, "11Г"))
vrazka.commit()                              # без commit записът не остава
vrazka.close()
  1. connect отваря файла и връща връзка (connection).
  2. cursor е „показалецът“, през който пращаме заявки и четем резултата — както SqlCommand в C#.
  3. execute(sql, параметри) изпълнява една заявка. Всяка ? в текста се запълва от кортежа отдясно, по ред.
  4. fetchall връща всички редове като списък от кортежи; fetchone — само първия.
  5. commit потвърждава промените. Забравите ли го, INSERT и UPDATE изчезват при затваряне.

Същото, което знаете от C#

C# (ADO.NET, модул 4)Python (sqlite3)
връзкаnew SqlConnection(niz)sqlite3.connect("baza.db")
командаnew SqlCommand(sql, vrazka)cur.execute(sql, parametri)
параметър@ime + AddWithValue? + кортеж
четенеExecuteReader + Read()fetchall() → списък от кортежи
записExecuteNonQuery()execute + commit()
затварянеusingwith / close()

Защо параметрите са задължителни

Изкушението е да сглобите заявката с f-низ. Изглежда еднакво и работи… докато някой не напише нещо неочаквано в полето.

tarseno = "Ива' OR '1'='1"                       # това е въвел „потребителят“

sql = f"SELECT name FROM students WHERE name = '{tarseno}'"
print(sql)
# SELECT name FROM students WHERE name = 'Ива' OR '1'='1'   ← връща ВСИЧКИ

SQL инжекция (SQL injection)

Атака, при която потребителски текст се вмъква в заявката и променя смисъла ѝ — чете чужди данни, а при по-лоши права трие таблици.

С параметър текстът никога не се смесва с кода на заявката: базата получава отделно „шаблон с ?“ и отделно „стойност“, и стойността си остава просто низ, колкото и кавички да съдържа.

cur.execute("SELECT name FROM students WHERE name = ?", (tarseno,))
print(cur.fetchall())        # [] — няма ученик с такова странно име

Справката като таблица: pandas

Списък от кортежи е удобен за програмата, но не и за човека. pandas чете резултата от заявка направо в DataFrame — таблица с имена на колони, която Colab показва красиво и която умее да смята.

import pandas as pd

df = pd.read_sql("""
    SELECT c.name AS klas, ROUND(AVG(m.mark), 2) AS sreden
    FROM classes c
    JOIN students s ON s.class_id = c.id
    JOIN marks m ON m.student_id = s.id
    GROUP BY c.id
    ORDER BY sreden DESC
""", vrazka)

df                              # в Colab последният израз се показва като таблица
print(df.to_string(index=False))   # същото като чист текст
print(df["sreden"].mean())         # pandas смята върху колоните
  • read_sql(sql, vrazka) изпълнява заявката и връща DataFrame; параметри се подават с params=(…).
  • to_string() дава текст за печат, to_csv() — CSV, който в урок 24 ще подаваме на модела.
  • Кой смята — SQL или pandas? Групирането и AVG са работа на базата; pandas е за последната обработка и показването.

А MySQL?

Училищната база от уроци 8–9 е MySQL/MariaDB. От Python към нея се отива със същите пет думи, само библиотеката е друга и параметърът се пише %s вместо ?:

!pip -q install mysql-connector-python
import mysql.connector
from google.colab import userdata

vrazka = mysql.connector.connect(
    host="db.uchilishte.local", user="uchenik",
    password=userdata.get("DB_PAROLA"), database="uchilishte")
cur = vrazka.cursor()
cur.execute("SELECT name FROM students WHERE class_id = %s", (2,))
print(cur.fetchall())

Какво трябва да запомниш

  • sqlite3 е вграден в Python; базата е един файл.
  • Редът е connect → cursor → execute → fetchall, а при запис — и commit.
  • Стойностите влизат в заявката само през ? и кортеж. f-низ със SQL е SQL инжекция, която чака да се случи.
  • Параметрите и правата от урок 8 са две отделни защити — ползват се заедно.
  • pd.read_sql прави от справката DataFrame; смятането е в SQL, показването — в pandas.