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.
Ushbu bo‘lim mundarijasi
- SQLite - o'rnatishsiz baza
- Baza yaratish va jadval qo'shish
- Ma'lumot qo'shish (INSERT)
- Ma'lumot o'qish (SELECT)
- Yangilash va o'chirish
- Guruhlash va agregat funksiyalar
- Asosiy SQL buyruqlari
- Tashqi API bilan ishlash
- Status kodlari
- Xatolarga chidamli so'rov
- POST so'rov va parametrlar
- Testlar yozish
- 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.
Baza yaratish va jadval qo'shish #
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.")
Baza va jadval tayyor.
Ma'lumot qo'shish (INSERT) #
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()
4 ta yozuv qo'shildi
Hech qachon so'rovni f-satr bilan qurmang:
# 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:
# XAVFSIZ
kursor.execute("SELECT * FROM talabalar WHERE ism = ?", (ism,))
Ma'lumot o'qish (SELECT) #
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()
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 #
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")
Yangilandi: 1 ta yozuv
O'chirildi: 0 ta yozuv
with bilan ulanishwith 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 #
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()
Shahar Soni O'rtacha Maks
--------------------------------------
Samarqand 2 88.0 91
Buxoro 1 95.0 95
Toshkent 2 72.5 78
Asosiy SQL buyruqlari #
| Buyruq | Vazifasi |
|---|---|
CREATE TABLE | Jadval yaratish |
INSERT INTO | Yozuv qo'shish |
SELECT | Ma'lumot o'qish |
WHERE | Shart bo'yicha filtrlash |
ORDER BY | Tartiblash |
LIMIT | Natijalar sonini cheklash |
UPDATE | Yozuvni o'zgartirish |
DELETE | Yozuvni o'chirish |
GROUP BY | Guruhlash |
JOIN | Jadvallarni bog'lash |
Tashqi API bilan ishlash #
API - boshqa dastur bilan ma'lumot almashish interfeysi. Ular odatda JSON qaytaradi.
pip install requests
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']:,}")
Status: 200
Nomi: Python
Ochiq repo: 27
Obunachilar: 24,381
Status kodlari #
| Kod | Ma'nosi |
|---|---|
200 | OK - hammasi joyida |
201 | Yaratildi |
400 | So'rov noto'g'ri |
401 | Avtorizatsiya kerak |
403 | Taqiqlangan |
404 | Topilmadi |
429 | Juda ko'p so'rov |
500 | Serverda xatolik |
Xatolarga chidamli so'rov #
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")
Muvaffaqiyat: Python
POST so'rov va parametrlar #
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"},
# )
Jami topildi: 3,124,857
public-apis 312,445 yulduz
system-design-primer 278,102 yulduz
awesome-python 224,918 yulduz
- Har doim
timeoutko'rsating - aks holda dastur cheksiz kutib qolishi mumkin. - So'rovlar orasida pauza qo'ying (
time.sleep), aks holda429xatosi olasiz. - API kalitlarini hech qachon kodga yozmang -
.envfaylida yoki muhit o'zgaruvchisida saqlang.
Testlar yozish #
Kodingiz to'g'ri ishlashiga ishonch hosil qilish uchun:
# 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)
# 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)
python test_hisoblagich.py
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 metodi | Nimani 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 |
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.
kutubxona.py dasturini yozing:
- SQLite bazasida
kitoblarjadvalini yarating (id, nomi, muallif, yil, mavjudmi). kitob_qosh(),kitoblarni_ol(),kitob_qidir(soz)vaholatni_ozgartir(id)funksiyalarini yozing.- Barcha so'rovlarda
?parametrlarini ishlating. unittestbilan har bir funksiya uchun kamida bitta test yozing.- Qo'shimcha:
requestsbilan 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.Rownatijalarni nom bo'yicha o'qish imkonini beradi.requestsbilan API'ga so'rov yuborasiz;timeoutva xato ushlash majburiy.unittestkodingiz to'g'ri ishlashini avtomatik tekshiradi.
Keyingi va yakuniy bo'limda barcha bilimlarni birlashtirib, to'liq amaliy loyiha yaratamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.