Darslik · 2026-08-16 · ~5 daqiqa o‘qiladi · boshlang'ich
Alembic: ishlab turgan bazani buzmasdan o'zgartirish
Mundarija
Avvalgi qismda klinika API'sini qurdik va
jadvallarni create_all bilan yaratdik. Oxirida bitta savol ochiq qolgan
edi: Doctor modeliga yangi maydon qo'shsak nima bo'ladi? Sinab ko'ring —
hech narsa bo'lmaydi. create_all faqat yo'q jadvalni yaratadi, borini
o'zgartirmaydi. Lokalda bazani o'chirib qaytadan yaratish mumkin, lekin
ichida haqiqiy yozuvlar turgan serverda bu yo'l yopiq.
Django'dan kelganlar uchun bu tanish muammo — u yerda makemigrations va
migrate bor edi. FastAPI o'z ORM'iga ega bo'lmagani uchun bu ish alohida
asbobga yuklangan: Alembic — SQLAlchemy oilasining rasmiy migratsiya
vositasi, SQLModel bilan ham bemalol ishlaydi.
Sozlash: bir marta qilinadigan ish#
uv add alembic
uv run alembic init migrations
Ikkinchi buyruq loyihada yangi papka va fayl ochadi:
.
├── alembic.ini ← asosiy sozlama
├── migrations/
│ ├── env.py ← Alembic'ning "miyasi" — shu faylni sozlaymiz
│ └── versions/ ← migratsiya fayllari shu yerga tushadi
└── app/
├── models.py
└── database.py
Ikki joyga tegamiz. Avval alembic.inida baza manzilini ko'rsatamiz:
# alembic.ini
sqlalchemy.url = sqlite:///clinic.db
Keyin env.pyga modellarimizni tanishtiramiz — Alembic "hozir baza qanday
bo'lishi kerak"ligini bilishi uchun aynan shu kerak:
# migrations/env.py — mavjud faylda ikki joyni o'zgartiramiz
# 1) yuqoriga import qo'shamiz. Modellar import bo'lishi SHART —
# aks holda Alembic ularni "ko'rmaydi"
from sqlmodel import SQLModel
from app import models # noqa: F401
# 2) target_metadata = None qatorini almashtiramiz:
target_metadata = SQLModel.metadata
Bitta mayda, lekin tishlaydigan joy: migratsiya fayllari ichida SQLModel
tiplari ishlatiladi, shuning uchun migrations/script.py.mako shabloniga
bitta import qo'shib qo'ying:
# migrations/script.py.mako ichida, boshqa importlar yoniga:
import sqlmodel
Birinchi migratsiya#
Baza allaqachon create_all bilan yaratilgan bo'lsa ham, tarixni toza
boshlaymiz — Alembic'ka "hozirgi holatni suratga ol" deymiz:
uv run alembic revision --autogenerate -m "boshlang'ich holat"
versions/ papkasida yangi fayl paydo bo'ladi. Uni ochib o'qing — ichida
upgrade() (o'zgarishni qo'llash) va downgrade() (orqaga qaytarish)
funksiyalari bor. Endi qo'llaymiz:
uv run alembic upgrade head
head — "eng oxirgi migratsiyagacha" degani. Alembic bazada alembic_version
degan kichik jadval ochib, qaysi migratsiyada turganini o'sha yerda eslab
qoladi.
Endi haqiqiy o'zgarish#
Modelga qabul narxini qo'shamiz:
# app/models.py
class Appointment(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
doctor_id: int = Field(foreign_key="doctor.id")
patient_name: str
starts_at: datetime
price: int = Field(default=0) # ← yangi maydon
Va ish tartibi har doim bir xil uch qadam:
# 1) farqni avtomatik aniqlash
uv run alembic revision --autogenerate -m "appointment'ga narx qo'shildi"
# 2) yaratilgan faylni O'QIB CHIQISH (pastdagi ogohlantirishga qarang)
# 3) qo'llash
uv run alembic upgrade head
Xato qildingizmi — bir qadam orqaga qaytish ham bor: alembic downgrade -1.
Autogenerate — yordamchi, hukmdor emas
--autogenerate modellar bilan bazani solishtirib farqni yozadi, lekin
hamma narsani ko'ravermaydi: ustun nomi o'zgarganini "o'chir + yarat"
deb tushunadi (ma'lumot yo'qoladi!), server_default'lar va ba'zi
cheklovlarni o'tkazib yuboradi. Shuning uchun qoida qat'iy: yaratilgan
migratsiya faylini har doim o'qib chiqing, ayniqsa ichida
drop_column yoki drop_table ko'rsangiz bir to'xtang — bu odatda
siz kutgan narsa emas.
SQLite bilan ishlayotganlarga bitta sozlama#
SQLite ALTER TABLEning ko'p turini bilmaydi — ustun o'chirish yoki
o'zgartirishda Alembic xato beradi. Buning tayyor yechimi bor, env.pyda
bitta parametr:
# migrations/env.py, context.configure(...) ichiga:
render_as_batch = True # SQLite uchun: jadvalni qayta qurish orqali ALTER
Shu rejimda Alembic o'zgarishni "yangi jadval yasab, ma'lumotni ko'chirib, eskisini o'chirish" usulida bajaradi — SQLite'da boshqa iloj yo'q, PostgreSQL'ga o'tganingizda esa bu parametr shunchaki bekor ishlaydi.
Productionda qayerda turadi#
Migratsiya lokal o'yinchoq emas, deploy zanjirining doimiy qadami.
CI/CD maqolasida ko'rgan deploy skriptida
Django'ning migrate buyrug'i turgan edi — FastAPI loyihasida o'sha o'rinni
shu buyruq egallaydi:
# scripts/deploy.sh ichida, xizmatni restart qilishdan OLDIN:
uv run alembic upgrade head
Tartib muhim: avval baza yangi holatga keladi, keyin yangi kod ishga tushadi.
Yakun#
Alembic bilan ishlash uch buyruqqa sig'adi: revision --autogenerate farqni
yozadi, siz faylni o'qib tasdiqlaysiz, upgrade head qo'llaydi. Eng muhim
odat — o'qish qadami: avtomatika yozgan migratsiya sizning niyatingizni emas,
o'z tushunganini aks ettiradi, ikkalasining farqi esa ba'zan bir ustunlik
ma'lumotga teng bo'ladi.
Shu bilan FastAPI juftligi yakunlandi. Keyingi o'quv maqolalari Django tomonga o'tadi: pytest-django bilan birinchi testni yozish — test nima uchun kerak degan savoldan ishlaydigan test faylgacha.