19-bo‘lim

Ma'lumotlar bazasi va API

SQLite bilan ma'lumotlarni saqlash, SQL so'rovlar, requests kutubxonasi orqali tashqi API bilan ishlash va testlar yozish.

🕑 13 daqiqa o‘qish 📄 576 so‘z 👁 5 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. SQLite - o'rnatishsiz baza
  2. Baza yaratish va jadval qo'shish
  3. Ma'lumot qo'shish (INSERT)
  4. Ma'lumot o'qish (SELECT)
  5. Yangilash va o'chirish
  6. Guruhlash va agregat funksiyalar
  7. Asosiy SQL buyruqlari
  8. Tashqi API bilan ishlash
  9. Status kodlari
  10. Xatolarga chidamli so'rov
  11. POST so'rov va parametrlar
  12. Testlar yozish
  13. Xulosa

Fayllar kichik ma'lumot uchun yaxshi. Lekin minglab yozuvni saqlash, qidirish va yangilash kerak bo'lganda ma'lumotlar bazasi kerak bo'ladi.

SQLite - o'rnatishsiz baza #

SQLite butun bazani bitta faylda saqlaydi va Python bilan birga keladi - hech narsa o'rnatish shart emas.

talabalar jadvali id ism shahar baho 1 Husanboy Qodirov Samarqand 85 2 Sardor Aliyev Toshkent 78 kalit ustunlar (maydonlar) qatorlar = yozuvlar
Ma'lumotlar bazasi jadvali - ustunlar va qatorlardan iborat

Baza yaratish va jadval qo'shish #

Python
import sqlite3

ulanish = sqlite3.connect("maktab.db")
kursor = ulanish.cursor()

kursor.execute("""
    CREATE TABLE IF NOT EXISTS talabalar (
        id      INTEGER PRIMARY KEY AUTOINCREMENT,
        ism     TEXT    NOT NULL,
        yosh    INTEGER NOT NULL,
        shahar  TEXT,
        baho    INTEGER DEFAULT 0
    )
""")

ulanish.commit()
ulanish.close()
print("Baza va jadval tayyor.")
Natija
Baza va jadval tayyor.

Ma'lumot qo'shish (INSERT) #

Python
import sqlite3

ulanish = sqlite3.connect("maktab.db")
kursor = ulanish.cursor()

# Bitta yozuv
kursor.execute(
    "INSERT INTO talabalar (ism, yosh, shahar, baho) VALUES (?, ?, ?, ?)",
    ("Husanboy Qodirov", 25, "Namangan", 85)
)

# Bir nechta yozuv
talabalar = [
    ("Sardor Aliyev", 25, "Toshkent", 78),
    ("Malika Yusupova", 21, "Buxoro", 95),
    ("Bekzod Rasulov", 26, "Toshkent", 67),
    ("Nodira Sobirova", 20, "Namangan", 91),
]
kursor.executemany(
    "INSERT INTO talabalar (ism, yosh, shahar, baho) VALUES (?, ?, ?, ?)",
    talabalar
)

ulanish.commit()
print(f"{kursor.rowcount} ta yozuv qo'shildi")
ulanish.close()
Natija
4 ta yozuv qo'shildi
SQL inyeksiyasidan himoya

Hech qachon so'rovni f-satr bilan qurmang:

Python
# XAVFLI!
ism = input("Ism: ")
kursor.execute(f"SELECT * FROM talabalar WHERE ism = '{ism}'")

Foydalanuvchi '; DROP TABLE talabalar; -- deb kiritsa, butun jadval o'chib ketadi. Har doim ? parametrlarini ishlating:

Python
# XAVFSIZ
kursor.execute("SELECT * FROM talabalar WHERE ism = ?", (ism,))

Ma'lumot o'qish (SELECT) #

Python
import sqlite3

ulanish = sqlite3.connect("maktab.db")
ulanish.row_factory = sqlite3.Row      # natijani lug'at kabi olish
kursor = ulanish.cursor()

# Barcha yozuvlar
kursor.execute("SELECT * FROM talabalar ORDER BY baho DESC")
qatorlar = kursor.fetchall()

print(f"{'ID':<4}{'Ism':<20}{'Yosh':>5}{'Shahar':<14}{'Baho':>6}")
print("-" * 50)
for qator in qatorlar:
    print(f"{qator['id']:<4}{qator['ism']:<20}{qator['yosh']:>5}  "
          f"{qator['shahar']:<14}{qator['baho']:>4}")

# Shart bilan
kursor.execute("SELECT ism, baho FROM talabalar WHERE baho >= ?", (85,))
print("\nA'lochilar:")
for ism, baho in kursor.fetchall():
    print(f"  {ism} - {baho}")

ulanish.close()
Natija
ID  Ism                  Yosh Shahar         Baho
--------------------------------------------------
3   Malika Yusupova        21  Buxoro          95
5   Nodira Sobirova        20  Namangan        91
1   Husanboy Qodirov       25  Namangan        85
2   Sardor Aliyev          25  Toshkent        78
4   Bekzod Rasulov         26  Toshkent        67

A'lochilar:
  Malika Yusupova - 95
  Nodira Sobirova - 91
  Husanboy Qodirov - 85

Yangilash va o'chirish #

Python
import sqlite3

with sqlite3.connect("maktab.db") as ulanish:
    kursor = ulanish.cursor()

    # Yangilash
    kursor.execute("UPDATE talabalar SET baho = ? WHERE ism = ?", (72, "Bekzod Rasulov"))
    print(f"Yangilandi: {kursor.rowcount} ta yozuv")

    # O'chirish
    kursor.execute("DELETE FROM talabalar WHERE baho < ?", (70,))
    print(f"O'chirildi: {kursor.rowcount} ta yozuv")
Natija
Yangilandi: 1 ta yozuv
O'chirildi: 0 ta yozuv
with bilan ulanish

with sqlite3.connect(...) bloki tugaganda commit() avtomatik bajariladi (xato bo'lsa rollback()). Bu qulay, lekin ulanishning o'zini yopmaydi - katta dasturlarda close() ni ham yozing.

Guruhlash va agregat funksiyalar #

Python
import sqlite3

ulanish = sqlite3.connect("maktab.db")
kursor = ulanish.cursor()

kursor.execute("""
    SELECT shahar,
           COUNT(*)   AS soni,
           AVG(baho)  AS ortacha,
           MAX(baho)  AS eng_yuqori
    FROM talabalar
    GROUP BY shahar
    ORDER BY ortacha DESC
""")

print(f"{'Shahar':<14}{'Soni':>6}{'O‘rtacha':>11}{'Maks':>7}")
print("-" * 38)
for shahar, soni, ortacha, maksimal in kursor.fetchall():
    print(f"{shahar:<14}{soni:>6}{ortacha:>11.1f}{maksimal:>7}")

ulanish.close()
Natija
Shahar          Soni   O'rtacha   Maks
--------------------------------------
Samarqand          2       88.0     91
Buxoro             1       95.0     95
Toshkent           2       72.5     78

Asosiy SQL buyruqlari #

BuyruqVazifasi
CREATE TABLEJadval yaratish
INSERT INTOYozuv qo'shish
SELECTMa'lumot o'qish
WHEREShart bo'yicha filtrlash
ORDER BYTartiblash
LIMITNatijalar sonini cheklash
UPDATEYozuvni o'zgartirish
DELETEYozuvni o'chirish
GROUP BYGuruhlash
JOINJadvallarni bog'lash

Tashqi API bilan ishlash #

API - boshqa dastur bilan ma'lumot almashish interfeysi. Ular odatda JSON qaytaradi.

Terminal
pip install requests
Python
import requests

javob = requests.get("https://api.github.com/users/python")

print(f"Status: {javob.status_code}")

if javob.status_code == 200:
    malumot = javob.json()
    print(f"Nomi:        {malumot['name']}")
    print(f"Ochiq repo:  {malumot['public_repos']}")
    print(f"Obunachilar: {malumot['followers']:,}")
Natija
Status: 200
Nomi:        Python
Ochiq repo:  27
Obunachilar: 24,381

Status kodlari #

KodMa'nosi
200OK - hammasi joyida
201Yaratildi
400So'rov noto'g'ri
401Avtorizatsiya kerak
403Taqiqlangan
404Topilmadi
429Juda ko'p so'rov
500Serverda xatolik

Xatolarga chidamli so'rov #

Python
import requests


def apidan_ol(url: str, timeout: int = 10) -> dict | None:
    """API dan ma'lumot oladi va barcha xatolarni ushlaydi."""
    try:
        javob = requests.get(url, timeout=timeout)
        javob.raise_for_status()          # 4xx/5xx bo'lsa xato ko'taradi
        return javob.json()

    except requests.exceptions.Timeout:
        print("  [XATO] Server javob bermadi (timeout)")
    except requests.exceptions.ConnectionError:
        print("  [XATO] Internetga ulanib bo'lmadi")
    except requests.exceptions.HTTPError as xato:
        print(f"  [XATO] HTTP xatosi: {xato.response.status_code}")
    except ValueError:
        print("  [XATO] Javob JSON formatida emas")

    return None


malumot = apidan_ol("https://api.github.com/users/python")
if malumot:
    print(f"Muvaffaqiyat: {malumot['name']}")
else:
    print("Ma'lumot olinmadi")
Natija
Muvaffaqiyat: Python

POST so'rov va parametrlar #

Python
import requests

# Query parametrlar bilan GET
javob = requests.get(
    "https://api.github.com/search/repositories",
    params={"q": "language:python", "sort": "stars", "per_page": 3},
    timeout=10,
)

natijalar = javob.json()
print(f"Jami topildi: {natijalar['total_count']:,}\n")

for repo in natijalar["items"]:
    print(f"{repo['name']:<24}{repo['stargazers_count']:>10,} yulduz")

# POST so'rov (misol uchun)
# javob = requests.post(
#     "https://example.com/api/talabalar",
#     json={"ism": "Husanboy", "baho": 85},
#     headers={"Authorization": "Bearer TOKEN"},
# )
Natija
Jami topildi: 3,124,857

public-apis                     312,445 yulduz
system-design-primer            278,102 yulduz
awesome-python                  224,918 yulduz
API bilan ishlashda odob
  • Har doim timeout ko'rsating - aks holda dastur cheksiz kutib qolishi mumkin.
  • So'rovlar orasida pauza qo'ying (time.sleep), aks holda 429 xatosi olasiz.
  • API kalitlarini hech qachon kodga yozmang - .env faylida yoki muhit o'zgaruvchisida saqlang.

Testlar yozish #

Kodingiz to'g'ri ishlashiga ishonch hosil qilish uchun:

Python
# hisoblagich.py
def qqs_hisobla(summa, foiz=12):
    if summa < 0:
        raise ValueError("Summa manfiy bo'lmasin")
    return summa * foiz / 100


def chegirma_qolla(summa, foiz):
    if not 0 <= foiz <= 100:
        raise ValueError("Foiz 0-100 oralig'ida bo'lsin")
    return summa - (summa * foiz / 100)
Python
# test_hisoblagich.py
import unittest
from hisoblagich import qqs_hisobla, chegirma_qolla


class QQSTestlari(unittest.TestCase):

    def test_oddiy_hisob(self):
        self.assertEqual(qqs_hisobla(1_000_000), 120_000)

    def test_boshqa_foiz(self):
        self.assertEqual(qqs_hisobla(1_000_000, 15), 150_000)

    def test_nol_summa(self):
        self.assertEqual(qqs_hisobla(0), 0)

    def test_manfiy_summa_xato_beradi(self):
        with self.assertRaises(ValueError):
            qqs_hisobla(-100)


class ChegirmaTestlari(unittest.TestCase):

    def test_chegirma(self):
        self.assertEqual(chegirma_qolla(100_000, 20), 80_000)

    def test_notogri_foiz(self):
        with self.assertRaises(ValueError):
            chegirma_qolla(100_000, 150)


if __name__ == "__main__":
    unittest.main(verbosity=2)
Terminal
python test_hisoblagich.py
Natija
test_chegirma (__main__.ChegirmaTestlari) ... ok
test_notogri_foiz (__main__.ChegirmaTestlari) ... ok
test_boshqa_foiz (__main__.QQSTestlari) ... ok
test_manfiy_summa_xato_beradi (__main__.QQSTestlari) ... ok
test_nol_summa (__main__.QQSTestlari) ... ok
test_oddiy_hisob (__main__.QQSTestlari) ... ok

----------------------------------------------------------------------
Ran 6 tests in 0.001s

OK
Tekshiruv metodiNimani tekshiradi
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)x rost
assertFalse(x)x yolg'on
assertIn(a, b)a in b
assertIsNone(x)x is None
assertRaises(Xato)Xato ko'tarilishi
assertAlmostEqual(a, b)Kasr sonlarni taqqoslash
Test yozish odati

Yangi funksiya yozganingizda darhol 2-3 ta test yozing: oddiy holat, chegaraviy holat va xato holati. Bu vaqt sarfiga o'xshaydi, lekin kodni o'zgartirganingizda hech narsa buzilmaganiga ishonch beradi.

Amaliy topshiriq

kutubxona.py dasturini yozing:

  1. SQLite bazasida kitoblar jadvalini yarating (id, nomi, muallif, yil, mavjudmi).
  2. kitob_qosh(), kitoblarni_ol(), kitob_qidir(soz) va holatni_ozgartir(id) funksiyalarini yozing.
  3. Barcha so'rovlarda ? parametrlarini ishlating.
  4. unittest bilan har bir funksiya uchun kamida bitta test yozing.
  5. Qo'shimcha: requests bilan Open Library API dan kitob haqida ma'lumot olib ko'ring.

Xulosa #

  • SQLite o'rnatishsiz ishlaydigan, bitta faylda saqlanadigan baza.
  • SQL so'rovlarida har doim ? parametrlarini ishlating - bu SQL inyeksiyasidan himoya qiladi.
  • row_factory = sqlite3.Row natijalarni nom bo'yicha o'qish imkonini beradi.
  • requests bilan API'ga so'rov yuborasiz; timeout va xato ushlash majburiy.
  • unittest kodingiz to'g'ri ishlashini avtomatik tekshiradi.

Keyingi va yakuniy bo'limda barcha bilimlarni birlashtirib, to'liq amaliy loyiha yaratamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.