Belajar Django - Migrations & Data Management
Episode 7 of 27

Belajar Django - Migrations & Data Management

Mengelola skema database dengan makemigrations dan migrate, menulis custom migration serta data migration untuk transformasi data, lalu men- seed skema blog dengan fixtures JSON dan loaddata. Termasuk strategi menggabungkan migrasi antar developer tanpa konflik.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Model di episode 6 sudah didesain dengan rapi, tetapi database belum tahu apa-apa. Di episode ini kita menjalankan migrations — mekanisme Django untuk mengubah skema database secara bertahap dan bisa di-replay — lalu mengisi data awal lewat fixtures.

Mengapa episode ini penting? Karena di sinilah model Python dan database benar-benar bertemu. Migrations adalah satu-satunya cara aman mengubah skema di tim dan di produksi: setiap perubahan direkam sebagai file, di-review, dan dijalankan berurutan. Kesalahan migrasi di produksi bisa berarti downtime atau kehilangan data, jadi memahami cara kerjanya adalah keterampilan wajib.

makemigrations dan migrate

Model di episode 6 belum pernah dijalankan. Langkah pertamanya: lahirkan file migrasi, lalu terapkan:

Buat dan jalankan migrasi pertama
python manage.py makemigrations
python manage.py migrate

makemigrations membaca perubahan model dan menulis file ke blog/migrations/ — file Python yang menggambarkan perubahan skema, bukan mengeksekusi SQL langsung. migrate lalu menerapkan semua migrasi yang belum dijalankan, termasuk migrasi bawaan Django (admin, auth, sessions).

Verifikasi hasilnya:

Cek status dan query yang dihasilkan
python manage.py showmigrations
python manage.py sqlmigrate blog 0001

showmigrations menampilkan status semua migrasi (tanda [X] = sudah diterapkan). sqlmigrate menampilkan SQL mentah yang akan dijalankan — cara terbaik mempelajari apa yang sebenarnya terjadi di database. Query SQL yang dihasilkan ORM inilah yang menjadi materi pembahasan kita di episode 14.

Tip

Biasakan berpasangan: makemigrations lalu review isi file migrasi sebelum migrate. File migrasi adalah kode yang akan dijalankan di produksi — membaca diff-nya (lewat git) mencegah kejutan seperti kolom yang salah tipe atau constraint yang tidak sesuai harapan.

Alur kerja tim

Di project dengan banyak developer, dua orang bisa mengubah model bersamaan dan menghasilkan file migrasi dengan nomor yang sama (0002). Cara mengatasinya:

Periksa konflik migrasi
python manage.py makemigrations --check --dry-run
python manage.py makemigrations --merge

--check --dry-run gagal (exit code non-zero) jika ada model yang belum dibuatkan migrasinya — bagus untuk CI. --merge menggabungkan migrasi yang bercabang. Alur sehat: commit migrasi sebagai commit terpisah yang jelas, dan segera migrasikan begitu ditarik.

Membaca File Migrasi

File migrasi adalah Python biasa. Contoh isi hasil makemigrations:

Pythonblog/migrations/0001_initial.py
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
 
class Migration(migrations.Migration):
    initial = True
 
    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]
 
    operations = [
        migrations.CreateModel(
            name="Category",
            fields=[
                ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                ("name", models.CharField(max_length=100, unique=True)),
            ],
        ),
        migrations.CreateModel(
            name="Post",
            fields=[
                ("title", models.CharField(max_length=200)),
                ("category", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="blog.category", related_name="posts")),
            ],
        ),
    ]

dependencies mencantumkan migrasi yang harus jalan lebih dulu — termasuk AUTH_USER_MODEL yang kita singgung di episode 10. operations adalah daftar langkah: CreateModel, AddField, RemoveField, AlterField, DeleteModel. Setiap operasi adalah unit yang bisa di-rollback.

Custom Migration

Ketika perubahan skema butuh logika yang tidak bisa dinyatakan lewat model, tulis custom migration manual:

Buat migrasi kosong
python manage.py makemigrations blog --empty -n backfill_post_slugs

Lalu isi operasinya dengan RunPython:

Pythonblog/migrations/0002_backfill_post_slugs.py
from django.db import migrations
from django.utils.text import slugify
 
def backfill_slugs(apps, schema_editor):
    Post = apps.get_model("blog", "Post")
    for post in Post.objects.all():
        if not post.slug:
            post.slug = slugify(post.title)
            post.save(update_fields=["slug"])
 
def noop(apps, schema_editor):
    pass
 
class Migration(migrations.Migration):
    dependencies = [("blog", "0001_initial")]
 
    operations = [
        migrations.RunPython(backfill_slugs, noop),
    ]

Warning

Di dalam data migration, selalu pakai apps.get_model("blog", "Post")bukan import langsung from blog.models import Post. apps.get_model memberi "historical model" sesuai kondisi migrasi saat itu, sehingga migrasi tetap berjalan benar walau model berubah di versi berikutnya. Meng-import langsung adalah salah satu penyebab migrasi rusak yang paling umum.

Data Migration

Perbedaan custom migration di atas dan data migration: keduanya sama-sama RunPython, tetapi data migration fokus pada transformasi/backfill data, sering dipakai saat menambahkan kolom NOT NULL ke tabel yang sudah berisi data. Alur aman yang dipakai di produksi:

  1. AddField dengan null=True (migration 1).
  2. RunPython untuk mengisi nilai (migration 2).
  3. AlterField ke null=False (migration 3).

Tiga langkah ini mencegah kegagalan NOT NULL saat kolom baru ditambahkan ke baris yang sudah ada. Pola ini begitu umum sehingga layak dihafal.

Fixtures dan Seed Data

Untuk environment development, kalian butuh data contoh. Fixtures adalah file data (biasanya JSON) yang di-export/import dengan perintah bawaan:

Export dan import fixtures
python manage.py dumpdata blog --indent 2 > blog/fixtures/blog.json
python manage.py loaddata blog

dumpdata blog mengekspor semua tabel app blog ke JSON. loaddata blog membaca blog/fixtures/blog.json (Django mencari di folder fixtures/ tiap app) dan memasukkannya ke database. Fixtures juga bisa dipakai di manage.py test sebagai data awal — cara cepat menyiapkan data untuk testing di episode 15.

Seed data ke database baru
python manage.py migrate
python manage.py loaddata blog
python manage.py createsuperuser

Urutan ini menjadi rutinitas "provision database baru": migrasi skema, seed data, lalu buat user admin untuk masuk ke Django Admin episode 8.

Note

Fixtures cocok untuk data referensi (categories, tags) dan data development. Untuk data besar atau migrasi antar sistem yang kompleks, pertimbangkan tool seperti django-seed atau script management command — tetapi untuk lab devblog, fixtures JSON sudah lebih dari cukup.

Beralih ke PostgreSQL

Sampai sini SQLite melayani lab dengan baik. Saat siap produksi, ganti engine ke PostgreSQL dan install driver:

Install psycopg dan ganti engine
pip install "psycopg[binary]"
Pythonsettings.py - PostgreSQL
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "devblog",
        "USER": "devblog",
        "PASSWORD": "rahasia",
        "HOST": "127.0.0.1",
        "PORT": "5432",
    }
}

Lalu python manage.py migrate di database PostgreSQL yang baru. Kredensial di atas baru boleh mengarah ke environment variable di episode 16 — jangan pernah hardcode di kode yang ter-commit. Perbedaan perilaku SQLite vs PostgreSQL (misalnya case-sensitivity) akan terasa di episode 14.

Penutup

Inti yang harus dibawa pulang:

  • makemigrations menulis file migrasi; migrate menerapkannya; sqlmigrate menunjukkan SQL-nya.
  • Review file migrasi sebelum dijalankan; --check untuk CI, --merge untuk konflik cabang.
  • Data migration RunPython memakai apps.get_model — jangan import model langsung.
  • Pola aman kolom NOT NULL baru: AddField null → backfill → AlterField.
  • Fixtures (dumpdata/loaddata) untuk seed data development dan referensi.
  • PostgreSQL production butuh engine + kredensial yang nanti dipindah ke env (episode 16).

Di episode 8 selanjutnya kita memanfaatkan "batteries-included" yang paling menonjol: Django Admin — mengkustomisasi ModelAdmin dengan list_display, filter, search, inline, dan custom actions untuk membangun admin panel production-grade untuk CMS blog kita.

Belajar Django - Migrations & Data Management | Belajar Django