Mundarija (23)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. ORM nima va nega
- 2.2. Model klass (DeclarativeBase, Mapped)
- 2.3. Session (birlik ish)
- 2.4. relationship (bog'lanish)
- 2.5. So'rov (select, scalars)
- 2.6. CRUD (add, commit, delete)
- 2.7. ORM vs Core vs Django ORM
- 2.8. Qachon ORM, qachon Core
- 2.9. Asinxron SQLAlchemy 2.0 va FastAPI (AsyncSession)
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Model va CRUD
- Misol 2 — relationship (bog'lanish)
- Misol 3 — So'rovlar (filtr, saralash, agregat)
- Misol 4 — Amaliy: ORM bilan ilova
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
23.7-dars: SQLAlchemy ORM
23-QISM — BAZALAR VA ORM · 7-dars
1. Kirish va motivatsiya
23.6 dagi Core SQL'ni Python obyektlari (select, Table) bilan yozadi — lekin baribir jadval-markazli (satr, ustun). Ko'p ilovada biz obyekt bilan ishlash xohlaymiz: kurs.muallif.nom (JOIN emas), muallif.kurslar (ro'yxat). Bu — ORM (Object-Relational Mapping): jadval → klass, qator → obyekt, ustun → atribut.
SQLAlchemy ORM — Python'ning eng kuchli ORM'i. Django ORM 21.3-bob ga o'xshaydi, lekin mustaqil (freymvorksiz — FastAPI, Flask, skript bilan ishlaydi). Core ustida quriladi (ORM ostida Core so'rovlari). 2.0 uslubi — DeclarativeBase, Mapped, mapped_column (turli belgilar bilan).
Real vaziyat. Bir jamoa Core bilan yozardi — har so'rovda jadval, ustun, JOIN qo'lda. Ma'lumot obyektga aylantirish (row → dict → klass) takror kod edi. ORM'ga o'tdi: jadval → klass (Kurs), qator → obyekt, bog'lanish → atribut (kurs.muallif). So'rov obyekt qaytaradi (select(Kurs) → Kurs obyektlari), bog'langan ma'lumot avtomatik (muallif.kurslar). Kod tabiiy (Python obyektlari) va qisqa bo'ldi.
Bu darsda SQLAlchemy ORM'ni — model klasslari, relationship, Session'ni o'rganamiz.
Bu darsda:
- ORM nima va nega
- Model klass (
DeclarativeBase,Mapped,mapped_column) Session(birlik ish — Unit of Work)relationship(bog'lanish vaback_populates)- So'rov (
select,scalars) - CRUD (add, commit, delete)
- Asinxron SQLAlchemy 2.0 (
AsyncSession,async_sessionmaker,asyncpg) - FastAPI va Pydantic v2 integratsiyasi (
from_attributes=True) - ORM vs Core vs Django ORM
- Amaliy: ORM bilan ilova
ℹ Misollarda SQLAlchemy ORM (2.0, SQLite) bilan sinaladi.
2. Nazariya — chuqur tushuntirish
2.1. ORM nima va nega
ORM (Object-Relational Mapping) — jadval'ni Python klassga bog'laydi:
| Baza | Python (ORM) |
|---|---|
| Jadval | Klass (Kurs) |
| Qator | Obyekt (kurs) |
| Ustun | Atribut (kurs.narx) |
| Bog'lanish (FK) | Atribut (kurs.muallif) |
ORM — jadval'ni klassga, qatorni obyektga bog'laydi. SQL o'rniga Python obyektlari bilan ishlaysiz: kurs.narx (ustun emas), kurs.muallif (JOIN emas). SQLAlchemy ORM Core 23.6-bob ustida quriladi, Django ORM 21.3-bob ga o'xshaydi, lekin mustaqil.
2.2. Model klass (DeclarativeBase, Mapped)
Model — jadval'ni ifodalovchi klass (2.0 uslubi):
from sqlalchemy import String, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer) DeclarativeBase — barcha modellar asosi (bir marta). Model — undan meros klass; __tablename__ — jadval nomi. Mapped[tur] — atribut turi (tur belgisi); mapped_column(...) — ustun sozlamalari (primary_key, String(50)). Bu 21.3 Django model ga o'xshaydi.
2.3. Session (birlik ish)
Session — ORM bilan ishlash oynasi:
from sqlalchemy.orm import Session
with Session(engine) as s:
s.add(Kurs(nom="Python", narx=100)) # qo'shish
s.commit() # saqlash
kurs = s.get(Kurs, 1) # id bo'yicha
kurs.narx = 150 # o'zgartirish
s.commit() # avtomatik yangila Session(engine) — ORM oynasi (23.4 tranzaksiya kabi). s.add(obyekt) (qo'shish), s.commit() (saqlash), s.get(Klass, id) (id bo'yicha), s.delete(obyekt) (o'chir). Obyekt o'zgarishi avtomatik kuzatiladi (commit'da yoziladi) — "birlik ish" (unit of work).
2.4. relationship (bog'lanish)
relationship — modellar orasida bog'lanish:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Muallif(Base):
__tablename__ = "muallif"
id: Mapped[int] = mapped_column(primary_key=True)
kurslar: Mapped[list["Kurs"]] = relationship(back_populates="muallif")
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
muallif_id: Mapped[int] = mapped_column(ForeignKey("muallif.id"))
muallif: Mapped["Muallif"] = relationship(back_populates="kurslar") relationship() — modellar bog'lanishi (21.10 Django FK ga o'xshaydi). ForeignKey — baza darajasi; relationship — Python darajasi (muallif.kurslar ro'yxat, kurs.muallif obyekt). back_populates — ikki tomonli (bir tomon o'zgarsa, ikkinchi ham). JOIN yozmasdan bog'langan ma'lumot.
2.5. So'rov (select, scalars)
ORM'da Core select 23.6-bob ishlaydi, lekin obyekt qaytaradi:
from sqlalchemy import select
s.scalars(select(Kurs)).all() # barcha Kurs obyekt
s.scalars(select(Kurs).where(Kurs.narx > 100)).all() # filtr
s.scalars(select(Kurs).order_by(Kurs.narx)).all() # saralash
s.scalars(select(Kurs).where(Kurs.nom == "Python")).one() # bitta
s.get(Kurs, 1) # id bo'yicha s.scalars(select(Klass)) — obyektlar ro'yxati (.all(), .one(), .first()). select(Kurs).where(Kurs.narx > 100) — Core kabi 23.6-bob, lekin Kurs obyekt qaytaradi (satr emas). Kurs.narx — atribut (ustun). Bu 21.9 Django filter ga o'xshaydi.
2.6. CRUD (add, commit, delete)
To'liq CRUD:
# Create:
s.add(Kurs(nom="Python", narx=100)); s.commit()
# Read:
kurs = s.get(Kurs, 1)
# Update:
kurs.narx = 150; s.commit() # avtomatik kuzatiladi
# Delete:
s.delete(kurs); s.commit() CRUD: s.add() + commit() (yaratish), s.get()/scalars (o'qish), atribut o'zgarish + commit() (yangila — avtomatik), s.delete() + commit() (o'chir). Django 21.9-bob ga o'xshaydi, lekin commit() aniq (Django avtomatik). "Birlik ish" — o'zgarishlar to'planib, commit'da yoziladi.
2.7. ORM vs Core vs Django ORM
| Xususiyat | SQLAlchemy ORM | SQLAlchemy Core | Django ORM |
|---|---|---|---|
| Daraja | Obyekt | Jadval | Obyekt |
| Freymvork | Mustaqil | Mustaqil | Django |
| So'rov | select(Kurs) |
select(kurs.c) |
Kurs.objects |
| Commit | Aniq | Aniq | Avtomatik |
SQLAlchemy ORM — obyekt-markazli, mustaqil (har freymvork). Core 23.6-bob — jadval-markazli (murakkab so'rov). Django ORM 21.9-bob — obyekt, lekin Django'ga bog'liq. SQLAlchemy — FastAPI/Flask (20.8, 22.1) bilan; Django ORM — Django bilan. ORM ostida Core (Core ostida SQL).
2.8. Qachon ORM, qachon Core
| Holat | Tanlov |
|---|---|
| Oddiy CRUD | ORM |
| Bog'langan obyekt | ORM (relationship) |
| Murakkab hisobot | Core (yoki xom SQL) |
| To'liq nazorat | Core |
ORM — oddiy CRUD, bog'langan obyekt (kurs.muallif), tabiiy Python kod. Core 23.6-bob — murakkab so'rov (ko'p JOIN, agregat, hisobot), to'liq SQL nazorati. Ko'p ilovada ikkalasi: kundalik ish ORM, murakkab so'rov Core. SQLAlchemy ikkalasini beradi (bir kutubxona).
2.9. Asinxron SQLAlchemy 2.0 va FastAPI (AsyncSession)
Zamonaviy backendlarda (FastAPI, Sanic, Litestar) I/O operatsiyalari event loopni bloklamasligi shart. Sinxron Session.commit() yoki Session.execute() so'rov kutayotganda butun Python jarayonini to'xtatib qo'yadi.
Buning oldini olish uchun SQLAlchemy 2.0 da asinxron dvigatel va sessiya mavjud:
from typing import AsyncGenerator
from sqlalchemy import select
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from pydantic import BaseModel, ConfigDict
# 1. Asinxron dvigatel (PostgreSQL uchun asyncpg, SQLite uchun aiosqlite drayveri):
ASYNC_DATABASE_URL = "postgresql+asyncpg://foydalanuvchi:parol@localhost:5432/wisar_db"
# Test yoki mahalliy SQLite uchun: "sqlite+aiosqlite:///./wisar.db"
async_engine = create_async_engine(
ASYNC_DATABASE_URL,
echo=False,
pool_size=20, # ulanishlar puli hajmi
max_overflow=10, # eng yuqori yuklamada qo'shimcha ulanishlar
)
# 2. Asinxron sessiya fabrikasi:
AsyncSessionLocal = async_sessionmaker(
bind=async_engine,
class_=AsyncSession,
expire_on_commit=False, # commit'dan keyin atributlar xotirada qoladi (FastAPI serialization uchun muhim!)
autocommit=False,
autoflush=False,
)
# 3. FastAPI uchun Dependency (bog'liqlik):
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
# 4. Pydantic v2 Javob sxemasi (ORM rejimida):
class KursJavob(BaseModel):
id: int
nom: str
narx: int
model_config = ConfigDict(from_attributes=True)
# 5. FastAPI Endpoint:
# @app.get("/kurslar", response_model=list[KursJavob])
# async def kurslar_royxati(db: AsyncSession = Depends(get_db)):
# natija = await db.execute(select(Kurs).order_by(Kurs.id))
# kurslar = natija.scalars().all()
# return kurslar # Pydantic avtomatik ORM obyektini JSON'ga aylantiradi| Tushuncha | Sinxron (2.0) | Asinxron (2.0 Async) |
|---|---|---|
| Dvigatel | create_engine(...) |
create_async_engine(...) |
| Drayver | psycopg2, sqlite3 |
asyncpg, aiosqlite |
| Sessiya | Session(engine) |
AsyncSession (async with) |
| So'rov bajarish | s.execute(...) |
await s.execute(...) |
| Commit / Rollback | s.commit() |
await s.commit() |
| Obyektlarni olish | s.scalars(...) |
(await s.execute(...)).scalars().all() |
Senior+ qoidasi: async def endpointlar ichida hech qachon sinxron Session ishlatmang. Agar sinxron Session bo'lsa — yo oddiy def qiling (FastAPI uni alohida threadpoolda bajaradi), yoki AsyncSession + await orqali toza asinxron oqim quring.
3. Tez ma'lumotnoma
from sqlalchemy import create_engine, String, Integer, ForeignKey, select, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session
class Base(DeclarativeBase): pass
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer)
engine = create_engine("sqlite:///wisar.db")
Base.metadata.create_all(engine)
with Session(engine) as s:
s.add(Kurs(nom="Python", narx=100)); s.commit() # create
k = s.get(Kurs, 1) # read
k.narx = 150; s.commit() # update
lst = s.scalars(select(Kurs).where(Kurs.narx > 100)).all() # so'rov
s.delete(k); s.commit() # deleteORM komponentlari
DeclarativeBase — asos · Mapped/mapped_column — atribut · relationship — bog'lanish
Session — oyna · add/commit/delete · select/scalars — so'rov4. Batafsil misollar
Misollarda SQLAlchemy ORM (2.0, SQLite) bilan sinaladi.
Misol 1 — Model va CRUD
"""DeclarativeBase, Mapped, mapped_column (model); Session; add/commit/get/delete (CRUD)."""
import warnings
warnings.filterwarnings("ignore")
from sqlalchemy import Integer, String, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
class Base(DeclarativeBase):
pass
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer)
def main() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as s:
print("=== 1. Create (add + commit) ===")
s.add(Kurs(nom="Python", narx=100))
s.add(Kurs(nom="Go", narx=120))
s.commit()
print(" Python, Go qo'shildi")
print("\n=== 2. Read (get, select) ===")
k = s.get(Kurs, 1)
print(f" id=1: {k.nom}, {k.narx}")
hammasi = s.scalars(select(Kurs).order_by(Kurs.id)).all()
print(f" barcha: {[x.nom for x in hammasi]}")
print("\n=== 3. Update (atribut + commit) ===")
k.narx = 150
s.commit()
print(f" yangilangan narx: {s.get(Kurs, 1).narx}")
print("\n=== 4. Delete ===")
s.delete(s.get(Kurs, 2))
s.commit()
qolgan = s.scalars(select(Kurs)).all()
print(f" qolgan: {[x.nom for x in qolgan]}")
print(" ⭐ model klass + Session — obyekt bilan CRUD")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Create (add + commit) ===
Python, Go qo'shildi
=== 2. Read (get, select) ===
id=1: Python, 100
barcha: ['Python', 'Go']
=== 3. Update (atribut + commit) ===
yangilangan narx: 150
=== 4. Delete ===
qolgan: ['Python']
⭐ model klass + Session — obyekt bilan CRUDNima ko'rsatdi: 2.2, 2.3, 2.6-bo'limlar.
Misol 2 — relationship (bog'lanish)
"""relationship (bog'lanish); ForeignKey; back_populates; kurs.muallif / muallif.kurslar (JOIN'siz)."""
import warnings
warnings.filterwarnings("ignore")
from sqlalchemy import ForeignKey, Integer, String, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Muallif(Base):
__tablename__ = "muallif"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
kurslar: Mapped[list["Kurs"]] = relationship(back_populates="muallif")
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer)
muallif_id: Mapped[int] = mapped_column(ForeignKey("muallif.id"))
muallif: Mapped["Muallif"] = relationship(back_populates="kurslar")
def main() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as s:
print("=== 1. Bog'langan obyekt yaratish ===")
ali = Muallif(nom="Ali")
ali.kurslar = [Kurs(nom="Python", narx=100), Kurs(nom="Go", narx=120)]
s.add(ali)
s.commit()
print(" Ali + 2 kurs qo'shildi")
with Session(engine) as s:
print("\n=== 2. muallif.kurslar (bir → ko'p) ===")
m = s.get(Muallif, 1)
print(f" {m.nom} kurslari: {[k.nom for k in m.kurslar]}")
print("\n=== 3. kurs.muallif (ko'p → bir, JOIN'siz) ===")
k = s.get(Kurs, 1)
print(f" {k.nom} muallifi: {k.muallif.nom}")
print("\n=== 4. Bog'lanish bilan so'rov ===")
r = s.scalars(select(Kurs).where(Kurs.muallif_id == 1).order_by(Kurs.narx)).all()
print(f" Ali kurslari: {[k.nom for k in r]}")
print(" ⭐ relationship — bog'langan ma'lumot atribut kabi (JOIN'siz)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bog'langan obyekt yaratish ===
Ali + 2 kurs qo'shildi
=== 2. muallif.kurslar (bir → ko'p) ===
Ali kurslari: ['Python', 'Go']
=== 3. kurs.muallif (ko'p → bir, JOIN'siz) ===
Python muallifi: Ali
=== 4. Bog'lanish bilan so'rov ===
Ali kurslari: ['Python', 'Go']
⭐ relationship — bog'langan ma'lumot atribut kabi (JOIN'siz)Nima ko'rsatdi: 2.4-bo'lim.
Misol 3 — So'rovlar (filtr, saralash, agregat)
"""select + where/order_by (filtr, saralash); func (agregat); scalars (obyekt ro'yxati)."""
import warnings
warnings.filterwarnings("ignore")
from sqlalchemy import Integer, String, create_engine, func, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
class Base(DeclarativeBase):
pass
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer)
til: Mapped[str] = mapped_column(String(2))
def main() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as s:
s.add_all([
Kurs(nom="Python", narx=100, til="uz"),
Kurs(nom="JavaScript", narx=80, til="uz"),
Kurs(nom="Go", narx=120, til="en"),
Kurs(nom="Rust", narx=150, til="en"),
])
s.commit()
print("=== 1. where (filtr) ===")
r = s.scalars(select(Kurs).where(Kurs.narx >= 120)).all()
print(f" narx>=120: {[(k.nom, k.narx) for k in r]}")
print("\n=== 2. order_by (saralash) ===")
r = s.scalars(select(Kurs).order_by(Kurs.narx.desc())).all()
print(f" narx kamayuvchi: {[k.nom for k in r]}")
print("\n=== 3. func (agregat) ===")
soni = s.scalar(select(func.count()).select_from(Kurs))
ortacha = s.scalar(select(func.avg(Kurs.narx)))
print(f" soni: {soni}, o'rtacha: {round(ortacha, 1)}")
print("\n=== 4. group_by (til bo'yicha) ===")
r = s.execute(select(Kurs.til, func.count()).group_by(Kurs.til).order_by(Kurs.til)).all()
print(f" {[(row[0], row[1]) for row in r]}")
print(" ⭐ ORM so'rovlari — Core kabi, lekin obyekt qaytaradi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. where (filtr) ===
narx>=120: [('Go', 120), ('Rust', 150)]
=== 2. order_by (saralash) ===
narx kamayuvchi: ['Rust', 'Go', 'Python', 'JavaScript']
=== 3. func (agregat) ===
soni: 4, o'rtacha: 112.5
=== 4. group_by (til bo'yicha) ===
[('en', 2), ('uz', 2)]
⭐ ORM so'rovlari — Core kabi, lekin obyekt qaytaradiNima ko'rsatdi: 2.5-bo'lim.
Misol 4 — Amaliy: ORM bilan ilova
SQLAlchemy ORM bilan mini kutubxona — model, bog'lanish, CRUD, so'rov. Bu — real ORM ilovasining namunasi.
"""to'liq ORM ilova: model, relationship, CRUD, so'rov, agregat — obyekt bilan ishlash."""
import warnings
warnings.filterwarnings("ignore")
from sqlalchemy import ForeignKey, Integer, String, create_engine, func, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Muallif(Base):
__tablename__ = "muallif"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
kurslar: Mapped[list["Kurs"]] = relationship(back_populates="muallif")
class Kurs(Base):
__tablename__ = "kurs"
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(50))
narx: Mapped[int] = mapped_column(Integer)
muallif_id: Mapped[int] = mapped_column(ForeignKey("muallif.id"))
muallif: Mapped["Muallif"] = relationship(back_populates="kurslar")
def main() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as s:
print("=== 1. Ma'lumot yaratish (bog'langan) ===")
ali = Muallif(nom="Ali", kurslar=[Kurs(nom="Python", narx=100), Kurs(nom="Go", narx=120)])
vali = Muallif(nom="Vali", kurslar=[Kurs(nom="Rust", narx=150)])
s.add_all([ali, vali])
s.commit()
print(" 2 muallif, 3 kurs")
with Session(engine) as s:
print("\n=== 2. Hisobot (muallif → kurslar) ===")
for m in s.scalars(select(Muallif).order_by(Muallif.nom)):
print(f" {m.nom}: {[k.nom for k in m.kurslar]}")
print("\n=== 3. Filtr va yangilash ===")
k = s.scalars(select(Kurs).where(Kurs.nom == "Python")).one()
k.narx = 130
s.commit()
print(f" Python yangi narx: {k.narx}, muallif: {k.muallif.nom}")
print("\n=== 4. Agregat ===")
jami = s.scalar(select(func.sum(Kurs.narx)))
print(f" jami narx: {jami}, kurslar: {s.scalar(select(func.count()).select_from(Kurs))}")
print(" ⭐ ORM — obyekt bilan tabiiy ish (jadval, JOIN, satr emas)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot yaratish (bog'langan) ===
2 muallif, 3 kurs
=== 2. Hisobot (muallif → kurslar) ===
Ali: ['Python', 'Go']
Vali: ['Rust']
=== 3. Filtr va yangilash ===
Python yangi narx: 130, muallif: Ali
=== 4. Agregat ===
jami narx: 400, kurslar: 3
⭐ ORM — obyekt bilan tabiiy ish (jadval, JOIN, satr emas)Nima ko'rsatdi: 2.1–2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "ORM va Core bir xil" | ORM obyekt, Core jadval |
| "SQLAlchemy Django kerak" | Mustaqil (har freymvork) |
"commit avtomatik" |
Aniq (s.commit()) |
"relationship = FK" |
FK baza, relationship Python |
| "So'rov satr qaytaradi" | Obyekt (Kurs) |
| "ORM sekin, keraksiz" | Tabiiy, tez rivojlanish |
| "Session = ulanish" | ORM oynasi (birlik ish) |
| "ORM murakkab so'rov" | Murakkab — Core |
6. Keng tarqalgan xatolar va yechimlari
1. commit() unutish
s.add(Kurs(...)) # ⚠️ saqlanmaydi
s.add(Kurs(...)); s.commit() # ✅2. Sessionni yopmaslik
s = Session(engine) # ⚠️ yopilmaydi
with Session(engine) as s: ... # ✅3. Mapped turisiz
nom = mapped_column(String) # ⚠️ 2.0'da Mapped
nom: Mapped[str] = mapped_column(String(50)) # ✅4. back_populates mos kelmaslik
relationship(back_populates="kurs") # ❌ (atribut nomi kurslar)
relationship(back_populates="kurslar") # ✅5. Yopiq Session'da atribut o'qish
with Session(engine) as s: k = s.get(Kurs, 1)
k.muallif # ⚠️ Session yopiq
# Session ichida o'qi yoki expire_on_commit=False # ✅6. scalarssiz execute
s.execute(select(Kurs)).all() # Row tuple
s.scalars(select(Kurs)).all() # ✅ Kurs obyekt7. __tablename__ unutish
class Kurs(Base): ... # ⚠️ jadval nomi yo'q
class Kurs(Base): __tablename__ = "kurs" # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 23.6-dars (o'tilgan): Core — ORM ostida
- 23.8-dars: Alembic — ORM migratsiyasi
- 23.9-dars: N+1 muammosi — relationship yuklash
- 21.3-dars (o'tilgan): Django model — taqqoslash
- 20.8-dars (o'tilgan): FastAPI baza — SQLAlchemy ORM
8. Eng yaxshi amaliyotlar
2.0 uslubi (
Mapped,mapped_column).Sessionniwithbilan (avtomatik yopish).commit()ni unutma (o'zgarish saqlash).relationshipbilan bog'langan obyekt.scalars— obyekt ro'yxati.Oddiy CRUD ORM, murakkab so'rov Core.
back_populates— ikki tomonli bog'lanish.Model faylda, so'rov xizmat qatlamida.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # ORM nima?
2. # DeclarativeBase nima?
3. # Mapped nima?
4. # Session nima?
5. # relationship nima?
6. # back_populates nima?
7. # scalars nima?
8. # commit qachon?
9. # ORM vs Core?
10. # SQLAlchemy Django kerakmi?
11. # s.get nima?
12. # __tablename__ nima?Javoblar
- Jadvalni klassga bog'lash (obyekt bilan)
- Barcha modellar asosi
- Atribut turi (tur belgisi)
- ORM oynasi (birlik ish)
- Modellar bog'lanishi
- Ikki tomonli bog'lanish
- Obyekt ro'yxati
- O'zgarishni saqlaganda
- ORM obyekt, Core jadval
- Yo'q (mustaqil)
- id bo'yicha obyekt
- Jadval nomi
Vazifa 2: Xatolarni tuzating
1. s.add(Kurs(...)) # commit
2. s = Session(engine) # with
3. nom = mapped_column(String) # Mapped
4. s.execute(select(Kurs)).all() # scalars
5. class Kurs(Base): pass # __tablename__Javoblar
1. s.add(Kurs(...)); s.commit()
2. with Session(engine) as s: ...
3. nom: Mapped[str] = mapped_column(String(50))
4. s.scalars(select(Kurs)).all()
5. class Kurs(Base): __tablename__ = "kurs"Vazifa 3: Model va CRUD
To'liq ORM:
- Model klass
add,commitget,scalars- Update,
delete
Vazifa 4: Bog'lanish
relationship:
- Ikki model
ForeignKey,relationshipback_populatesobyekt.bog'lanisho'qish
Vazifa 5: So'rov
Murakkab:
where,order_byfunc(agregat)group_by- Bog'langan so'rov
Vazifa 6: ORM vs Core
Taqqoslash:
- Bir vazifa ORM bilan
- Bir vazifa Core bilan
- Farqni ko'rsatish
- Qaysi qachon
Vazifa 7: O'ylash
SQLAlchemy ORM jadvalni klassga, qatorni obyektga bog'laydi — SQL o'rniga Python obyektlari (kurs.muallif.nom) bilan ishlaysiz. Bu "impedans nomuvofiqligi" (impedance mismatch) ni — baza (jadval, satr) va dastur (obyekt) orasidagi farqni — kamaytiradi. ORM bu farqni yashiradi (obyekt kabi), lekin butunlay yashirolmaydi (N+1 muammosi, 23.9). "Abstraksiya foydasi va narxi" tamoyili — ORM nima uchun kod'ni soddalashtiradi, lekin qachan "abstraksiya oqadi" (leaky abstraction — SQL bilish kerak), va bu 23.9 bilan qanday bog'liq?
Javob
Qisqa javob: ORM baza (jadval, satr) va dastur (obyekt) orasidagi impedans nomuvofiqligini kamaytiradi — obyekt bilan ishlaysiz (kurs.muallif), SQL emas. Bu kod'ni soddalashtiradi (tabiiy Python, kam takror). Lekin abstraksiya oqadi (leaky): ORM SQL yaratadi, va agar bilmasangiz, sekin so'rov (N+1, 23.9), ortiqcha yuklash yuz beradi. "Abstraksiya foydasi va narxi" — foyda: soddalik (obyekt, SQL emas); narx: nazorat yo'qolishi (yaratilgan SQL yashirin), va murakkab holatda abstraksiya oqadi (SQL bilish kerak). 23.9 (N+1) — abstraksiya oqishining klassik misoli: for k: k.muallif — har biri SQL (ORM yashirgan). Yechim: ORM'ni tushunish (nima SQL yaratadi).
1. Impedans nomuvofiqligi
Baza (jadval, satr, JOIN) va dastur (obyekt, atribut, havola) — har xil model. ORM ularni moslashtiradi (jadval → klass). Lekin to'liq mos emas (oqadi).
2. Abstraksiya foydasi
| Foyda | Tafsilot |
|---|---|
| Soddalik | Obyekt (SQL emas) |
| Kam takror | CRUD avtomatik |
| Xavfsiz | Parametr (injection yo'q) |
| Portativ | Baza almashsa bir xil |
3. Abstraksiya narxi (oqadi)
| Narx | Tafsilot |
|---|---|
| Nazorat | Yaratilgan SQL yashirin |
| N+1 (23.9) | for k: k.muallif — har biri SQL |
| Sekin | Ortiqcha yuklash |
| SQL bilish | Baribir kerak (murakkabda) |
4. "Leaky abstraction" (oqadigan abstraksiya)
ORM SQL'ni yashiradi, lekin butunlay yashirolmaydi: sekin so'rovda SQL'ni ko'rish (echo=True), N+1'ni tuzatish 23.9-bob uchun SQL bilish kerak. Abstraksiya "oqadi" — ost qatlam (SQL) chiqadi.
5. 23.9 bilan bog'lik
23.9 (N+1): for kurs: kurs.muallif — har kurs.muallif alohida SQL (ORM yashirgan). Bu abstraksiya oqishi — ORM sodda ko'rinadi, lekin ost'da ko'p so'rov. Yechim: selectinload (oldindan yukla) — ORM'ni tushunish.
6. Muhandislik saboqlari
- Abstraksiya soddalashtiradi (foyda)
- Lekin nazorat yo'qotadi (narx)
- Murakkabda oqadi (SQL bilish)
- ORM'ni tushunish (nima SQL yaratadi)
7. Xulosa
- ORM impedans nomuvofiqligini kamaytiradi
- Foyda: soddalik (obyekt)
- Narx: nazorat (SQL yashirin)
- Oqadi: N+1 23.9-bob, SQL bilish kerak
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda SQLAlchemy ORM'ni o'rgandik.
Eng muhim uch fikr:
ORM — jadval'ni klassga, qatorni obyektga bog'laydi. ORM (Object-Relational Mapping) — jadval → klass (
Kurs), qator → obyekt, ustun → atribut (kurs.narx), FK → atribut (kurs.muallif). SQL o'rniga Python obyektlari bilan ishlaysiz. Model (2.0 uslubi):DeclarativeBase(asos),__tablename__(jadval nomi),Mapped[tur](atribut turi),mapped_column(...)(ustun sozlamalari). SQLAlchemy ORM Core 23.6-bob ustida quriladi, Django ORM 21.3-bob ga o'xshaydi, lekin mustaqil (har freymvork).Session,relationship, so'rov.Session(engine)— ORM oynasi (birlik ish):s.add()+s.commit()(yaratish),s.get(Klass, id)/s.scalars(select(Klass))(o'qish — obyekt), atribut o'zgarish +commit()(yangila — avtomatik kuzatiladi),s.delete()(o'chir).relationship()— modellar bog'lanishi (muallif.kurslarro'yxat,kurs.muallifobyekt — JOIN'siz),back_populates(ikki tomonli). So'rov:select(Kurs).where(Kurs.narx > 100)(Core kabi, lekin obyekt qaytaradi).ORM vs Core — qachon qaysi. ORM — obyekt-markazli (oddiy CRUD, bog'langan obyekt, tabiiy Python kod); Core 23.6-bob — jadval-markazli (murakkab so'rov, hisobot, to'liq SQL nazorati). Ko'p ilovada ikkalasi: kundalik ish ORM, murakkab so'rov Core (bir kutubxona). ORM abstraksiya baza va dastur orasidagi nomuvofiqlikni kamaytiradi, lekin "oqadi" (N+1, 23.9 — SQL bilish baribir kerak). SQLAlchemy — FastAPI/Flask bilan; Django ORM — Django bilan.
Keyingi darsda migratsiya va Alembic ni o'rganamiz: model o'zgarsa bazani qanday yangilash (21.4 Django migratsiya kabi, lekin SQLAlchemy uchun).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!