Mengelola perubahan skema database dengan Alembic lewat Flask-Migrate: inisialisasi dengan init, membuat revision dengan migrate, menerapkan dengan upgrade, data migration untuk transformasi data, dan versioning skema yang aman untuk produksi.

Di episode 10 kita memakai db.create_all() — nyaman saat skema pertama dibuat, tetapi tidak bisa menambah kolom pada tabel yang sudah ada. Bayangkan: kalian menambah field phone ke tabel user di produksi. Dengan create_all(), kolom itu tidak akan pernah dibuat, dan kode mulai error. Solusinya adalah database migrations — dan tool standarnya adalah Alembic, yang dibungkus Flask-Migrate.
Episode 11 mengajarkan alur init → migrate → upgrade, cara menulis revision manual untuk kasus khusus, dan data migration untuk transformasi data — praktik yang wajib dikuasai sebelum aplikasi menyentuh produksi.
Migration adalah versi skema database, persis seperti git untuk skema. Setiap perubahan (tambah kolom, ubah constraint, buat tabel) dicatat sebagai revision — satu file Python yang bisa dieksekusi maju (upgrade) atau mundur (downgrade).
20260816_1000_initial - create table user
20260816_1100_add_phone - add column phone
20260816_1200_add_email_unique - add unique constraint emailDengan migrations, tim kalian bisa menerapkan perubahan skema yang sama di development, staging, dan produksi — tanpa create_all() yang menebak-nebak.
Install dan daftarkan dengan pola extension (episode 9):
pip install "flask-migrate>=4.0"from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
migrate = Migrate()from app.extensions import db, migrate
def create_app(config) -> Flask:
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
migrate.init_app(app, db)
from app import models
return appmigrate.init_app(app, db) menghubungkan Alembic ke SQLAlchemy kalian. Catatan penting: hapus db.create_all() dari factory — perannya sekarang digantikan flask db upgrade.
Tiga perintah utama, dijalankan dari CLI flask:
flask --app run db initdb init membuat folder migrations/ — tempat semua revision tersimpan. Lakukan sekali per proyek dan commit folder ini.
flask --app run db migrate -m "add user phone"db migrate membandingkan model dengan database saat ini, lalu membuat file revision yang berisi perubahan. Contoh hasilnya:
def upgrade():
with op.batch_alter_table("user") as batch_op:
batch_op.add_column(sa.Column("phone", sa.String(20), nullable=True))
def downgrade():
with op.batch_alter_table("user") as batch_op:
batch_op.drop_column("phone")Selalu baca hasil db migrate — Alembic hebat, tetapi tidak selalu menebak intent kalian dengan tepat (misal default yang salah, atau salah deteksi rename).
flask --app app run db upgradedb upgrade menjalankan semua revision yang belum diterapkan, berurutan. Dari sini alurnya repetitif: ubah model → db migrate → review → db upgrade. Di CI/CD, db upgrade menjadi langkah wajib sebelum deploy (episode 23).
Tip
Biasakan memeriksa revision yang dihasilkan sebelum upgrade, dan test di database development dulu. Kebiasaan "create → migrate → upgrade → review diff" mencegah revision janggal yang bisa memblokir produksi. flask db history menampilkan daftar revision; flask db current menunjukkan posisi kalian.
Setiap revision punya downgrade() — kebalikan dari upgrade():
flask --app run db downgradeIni berguna saat kalian salah menerapkan di development. Di produksi, downgrade bukan alur normal — lebih aman maju dengan revision baru yang membalik perubahan, agar tim lain yang sudah menerapkan tidak kehilangan riwayat.
Tidak semua perubahan adalah skema. Kadang kalian perlu mengubah isi data — misalnya menggabungkan dua kolom, atau mengisi nilai default untuk baris lama:
def upgrade():
with op.batch_alter_table("user") as batch_op:
batch_op.add_column(sa.Column("full_name", sa.String(120), nullable=True))
# transformasi data setelah kolom dibuat
op.execute(
"""
UPDATE "user"
SET full_name = first_name || ' ' || last_name
WHERE full_name IS NULL
"""
)Urutannya krusial: buat kolom dulu, lalu isi data, baru (jika perlu) tambahkan constraint NOT NULL. Untuk transformasi kompleks, operasi data sebaiknya idempotent dan diuji terhadap snapshot database — karena sekali jalan di produksi, sulit dibatalkan.
Beberapa aturan yang membuat migrations aman di tim:
migrations/: revision adalah bagian dari codebase; jangan di-gitignore.flask db merge heads.batch_alter_table untuk SQLite: SQLite tidak mendukung ALTER TABLE penuh — pola with op.batch_alter_table(...) meniru ulang tabel secara aman (Flask-Migrate menyarankannya).Warning
Menghapus kolom yang masih dipakai kode lama, atau migration yang gagal di tengah jalan di produksi, adalah dua skenario tersulit. Mitigasinya: test migration di database copy, jalankan db upgrade saat low-traffic, dan selalu punya backup database sebelum menerapkan migration besar.
db migrate setelah ubah model: skema database tidak ikut berubah — error no such column.db migrate tidak mendeteksi perubahan: pastikan folder migrations/ ada dan model di-import di factory.create_all() masih ada di factory: double source of truth — hapus, gunakan db upgrade.Pada episode 11 ini, kalian telah menguasai versioning skema dengan Alembic.
Inti yang harus dibawa pulang:
flask db init → flask db migrate -m "..." → review → flask db upgrade.upgrade() dan downgrade(); baca hasil generate sebelum menerapkan.op.execute) untuk transformasi data, bukan hanya skema.migrations/, jangan edit revision yang sudah di-merge.Di episode 12 selanjutnya, kita menangani input dari pengguna: forms & validation — WTForms/Flask-WTF, proteksi CSRF, validators, field rendering, dan validasi server-side yang benar. Sampai jumpa di episode 12!