IlmHamroh
Python kursi/Bazalar va ORM7/12-dars18 daqiqa
Mundarija (23)

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 va back_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):

python
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:

python
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:

python
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:

python
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:

python
# 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:

python
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

python
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()                               # delete

ORM komponentlari

DeclarativeBase — asos · Mapped/mapped_column — atribut · relationship — bog'lanish
Session — oyna · add/commit/delete · select/scalars — so'rov

4. Batafsil misollar

Misollarda SQLAlchemy ORM (2.0, SQLite) bilan sinaladi.

Misol 1 — Model va CRUD

python
"""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:

text
=== 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 CRUD

Nima ko'rsatdi: 2.2, 2.3, 2.6-bo'limlar.

Misol 2 — relationship (bog'lanish)

python
"""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:

text
=== 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)

python
"""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:

text
=== 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 qaytaradi

Nima 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.

python
"""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:

text
=== 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

python
s.add(Kurs(...))                              # ⚠️ saqlanmaydi
s.add(Kurs(...)); s.commit()                  # ✅

2. Sessionni yopmaslik

python
s = Session(engine)                           # ⚠️ yopilmaydi
with Session(engine) as s: ...                # ✅

3. Mapped turisiz

python
nom = mapped_column(String)                   # ⚠️ 2.0'da Mapped
nom: Mapped[str] = mapped_column(String(50))  # ✅

4. back_populates mos kelmaslik

python
relationship(back_populates="kurs")           # ❌ (atribut nomi kurslar)
relationship(back_populates="kurslar")        # ✅

5. Yopiq Session'da atribut o'qish

python
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

python
s.execute(select(Kurs)).all()                 # Row tuple
s.scalars(select(Kurs)).all()                 # ✅ Kurs obyekt

7. __tablename__ unutish

python
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

  1. 2.0 uslubi (Mapped, mapped_column).

  2. Sessionni with bilan (avtomatik yopish).

  3. commit()ni unutma (o'zgarish saqlash).

  4. relationship bilan bog'langan obyekt.

  5. scalars — obyekt ro'yxati.

  6. Oddiy CRUD ORM, murakkab so'rov Core.

  7. back_populates — ikki tomonli bog'lanish.

  8. Model faylda, so'rov xizmat qatlamida.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
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
  1. Jadvalni klassga bog'lash (obyekt bilan)
  2. Barcha modellar asosi
  3. Atribut turi (tur belgisi)
  4. ORM oynasi (birlik ish)
  5. Modellar bog'lanishi
  6. Ikki tomonli bog'lanish
  7. Obyekt ro'yxati
  8. O'zgarishni saqlaganda
  9. ORM obyekt, Core jadval
  10. Yo'q (mustaqil)
  11. id bo'yicha obyekt
  12. Jadval nomi

Vazifa 2: Xatolarni tuzating

python
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
python
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:

  1. Model klass
  2. add, commit
  3. get, scalars
  4. Update, delete

Vazifa 4: Bog'lanish

relationship:

  1. Ikki model
  2. ForeignKey, relationship
  3. back_populates
  4. obyekt.bog'lanish o'qish

Vazifa 5: So'rov

Murakkab:

  1. where, order_by
  2. func (agregat)
  3. group_by
  4. Bog'langan so'rov

Vazifa 6: ORM vs Core

Taqqoslash:

  1. Bir vazifa ORM bilan
  2. Bir vazifa Core bilan
  3. Farqni ko'rsatish
  4. 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

  1. Abstraksiya soddalashtiradi (foyda)
  2. Lekin nazorat yo'qotadi (narx)
  3. Murakkabda oqadi (SQL bilish)
  4. ORM'ni tushunish (nima SQL yaratadi)

7. Xulosa

  1. ORM impedans nomuvofiqligini kamaytiradi
  2. Foyda: soddalik (obyekt)
  3. Narx: nazorat (SQL yashirin)
  4. 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:

  1. 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).

  2. 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.kurslar ro'yxat, kurs.muallif obyekt — JOIN'siz), back_populates (ikki tomonli). So'rov: select(Kurs).where(Kurs.narx > 100) (Core kabi, lekin obyekt qaytaradi).

  3. 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).

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
23.7-dars: SQLAlchemy ORM — IlmHamroh