Featured image of post Pengaturan Database Django

Pengaturan Database Django

Memahami konfigurasi database Django, perbedaan SQLite dan PostgreSQL, serta konsep migrations sebagai version control untuk schema database.

Pengaturan Database Django

Overview

Di settings.py sudah ada kode berikut:

1
2
3
4
5
6
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

Ini adalah konfigurasi SQLite default milik Django. Sebelum kita utak-atik, kita pahami dulu konsepnya.


Memahami Dictionary DATABASES pada settings.py

Dictionary DATABASES bisa menyimpan beberapa koneksi database. Key 'default' adalah penanda bahwa Django akan otomatis menggunakan itu, kecuali kita tentukan secara jelas yang mana yang ingin digunakan.

Minimal setiap koneksi database butuh dua key:

KeyFungsi
ENGINEDatabase backend yang mau dipakai (driver-nya)
NAMENama database-nya (untuk SQLite, ini path dari file-nya)

Untuk SQLite, NAME itu berupa path dari file (db.sqlite3 dibuat di BASE_DIR, yaitu folder my-drf-project/). Untuk PostgreSQL, NAME itu logical name database di server.


SQLite vs PostgreSQL

SQLite (yang digunakan saat ini, cukup buat belajar)

1
2
3
4
5
6
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

Kenapa SQLite sudah cukup buat belajar:

  • Zero configuration, tidak perlu install atau menjalankan server apapun
  • Seluruh database cuma satu file (db.sqlite3)
  • Django sudah include driver SQLite bawaan, nggak perlu melakukan pip install

Kenapa tidak cocok buat production:

  • Tidak mendukung concurrent write (hanya satu proses write dalam satu waktu)
  • Tidak dirancang untuk environment multi-process atau networked
  • Fitur SQL-nya terbatas dibandingkan dengan PostgreSQL
  • File-nya ada di local disk server, tidak ada replikasi dan tidak high availability

PostgreSQL (standar untuk production)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'myproject_db',     # logical name database in Postgres
        'USER': 'myproject_user',   # role/user Postgres
        'PASSWORD': 'strongpassword',
        'HOST': 'localhost',        # atau '127.0.0.1', atau hostname remote
        'PORT': '5432',             # default port Postgres
    }
}

Langkah tambahan jika menggunakan PostgreSQL:

  • Install Python adapter: pip install psycopg2-binary (untuk development) atau psycopg2 (production, butuh libpq di level system)
  • Buat database dan user di PostgreSQL (CREATE DATABASE, CREATE USER)
  • Update requirements.txt

Kenapa menggunakan PostgreSQL untuk production:

  • Full ACID compliance dengan dukungan concurrency yang bagus
  • Ada JSON fields, full-text search, array types, yang sering digunakan di DRF API
  • Sudah terbukti pada sistem dengan skala besar (dipakai oleh Instagram, Heroku, dll.)
  • Mendukung connection pooling dengan tools seperti PgBouncer

Best practice: jangan taruh credentials langsung di settings.py, gunakan environment variables:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import os

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME', 'myproject_db'),
        'USER': os.environ.get('DB_USER', 'myproject_user'),
        'PASSWORD': os.environ.get('DB_PASSWORD', ''),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

Variabel-variabel tersebut ditaruh di file .env (di-load pakai python-decouple atau django-environ) dan jangan pernah di-commit ke git.

Saat ini kita akan tetap menggunakan SQLite

Kita membahas PostgreSQL hanya agar tahu bahwa pilihan PostgreSQL tersedia dan kenapa kita akan beralih ke sana nantinya. Di fase belajar ini kita tidak perlu menggunakan PostgreSQL.

SQLite sudah lebih dari cukup untuk semua yang akan kita kerjain selama awal proses belajar DRF seperti mendefiniskan models, menjalankan migrations, membuat serializers, menulis views, dan melakukan testing API endpoints.

Kita akan pindah ke PostgreSQL jika sudah di titik mau deploy project ke environment production. Jika waktunya tiba kita akan pindah ke PostgreSQL pun caranya sangat straightforward, tinggal update konfigurasi DATABASES di settings.py dan install psycopg2.


Apa Itu Migrations?

Migrations itu semacam version control untuk schema database kita. Isinya adalah file-file Python yang mendeskripsikan bagaimana cara mentransformasi database dari satu kondisi ke kondisi lain.

Agar mudah membayangkannya:

1
models.py  →  (makemigrations)  →  file migration  →  (migrate)  →  tabel database sebenarnya
  • models.py adalah sumber informasi yang paling utama, di situ kita mendefinisikan struktur data menggunakan Python
  • makemigrations membaca models kita, membandingkannya dengan state terakhir yang tercatat, lalu membuat file migration yang berisi deskripsi dari perubahan yang ada.
  • migrate membaca semua file migration yang belum dijalankan, kemudian melakukan eksekusi SQL-nya ke database sebenarnya.

Data migrasi disimpan pada folder migrations/

Sekarang app books/ kita belum punya folder migrations/ karena kita belum pernah menjalankan makemigrations. Setelah dijalanin, Django akan membuat:

1
2
3
4
books/
  migrations/
    __init__.py
    0001_initial.py   ← auto-generated, deskripsi schema awal kita

Setiap file diberikan nomor berurutan (0001_, 0002_, 0003_…) dan setiap file tahu migration mana yang jadi dependensinya.

Bayangkan migrations itu seperti tugas yang dikerjakan setelah tugas sebelumnya.

Anggap saja kita sedang membangun rumah, dan kita punya catatan apa yang kita bangun hari itu:

Entry 0001 — Membuat fondasi
Entry 0002 — Membangun dinding       (butuh 0001 selesai dulu)
Entry 0003 — Memasang atap           (butuh 0002 selesai dulu)
Entry 0004 — Memasang jendela        (butuh 0003 selesai dulu)

Kita tidak bisa pasang atap sebelum dindingnya ada. Setiap langkah bergantung pada langkah sebelumnya yang sudah selesai.

Migration pada Django juga bekerja dengan cara yang sama. Setiap migration, file migrasi tersebut berbicara secara internal: “Saya butuh migration sebelumnya sudah di-apply dulu.” Django membaca chain ini dan selalu menjalankan migration dalam urutan yang benar, tidak ada yang terlewat, tidak pernah acak secara urutan.

Pada praktiknya:

0001_initial.py            → bikin tabel Book dari nol
0002_add_isbn.py           → tambah kolom isbn ke tabel Book (perlu 0001 terlebih dahulu)
0003_add_published_date.py → tambah kolom published_date     (perlu 0002 terlebih dahulu)

Jika ada tim baru di project kita yang melakukan clone project dan menjalankan python manage.py migrate, Django melihat ketiga file itu, memahami urutannya, dan menjalankannya satu per satu secara berurutan, membangun database dari nol sampai ke kondisi terbaru.

Intinya: kita tidak perlu kuatir mengenai urutan migrasi. Django memantau itu secara otomatis lewat dependency chain yang sudah ada pada tiap file.


Migrations dalam Konteks API Development

API selalu berkembang. Kita akan terus menambah field baru, membuat model baru, melakukan rename terhadap banyak hal. Pada setiap perubahan perlu migration. Contoh realnya:

1
2
3
4
0001_initial.py            → Model Book dengan title, author
0002_add_isbn.py           → Tambah field isbn ke Book
0003_add_published_date.py → Tambah field published_date
0004_rename_author.py      → Rename author jadi author_name

Di DRF API, ini sangat penting karena:

  • Serializer kita merupakan gambaran dari field pada model. Jika migration belum dijalankan, maka kolom di database belum ada, dan API kita akan crash pas saat membaca/menulis ke kolom tersebut.
  • App bawaan Django (auth, admin, sessions, contenttypes) juga punya migrationnya sendiri yang perlu diapply. Itu sebabnya saat pertama kali migrate di project baru, ada sekitar 18 migration yang dijalankan meski kita belum membuat satu model pun.

Kenapa Migrations Penting Pada Team Project

Ini penting. Bayangkan kita dan team kita sedang mengerjakan codebase yang sama:

Tanpa migrations:

  • Kita menambahkan field published_date ke model Book
  • Team kita melakukan pull code
  • Database mereka masih schema yang lama, nggak ada kolom published_date
  • Di mereka, APInya akan crash

Dengan migrations:

  • makemigrations akan generate 0003_add_published_date.py
  • Kita commit file tersebut ke git
  • Team kita pull code dan jalanin migrate
  • Django menerapkan migration baru, database mereka langsung tersinkronisasi
  • Tidak perlu menuliskan SQL ALTER TABLE secara manual

Hal Penting: File migration wajib masuk ke git

Selalu commit folder migrations/. Jangan pernah ditambahkan ke .gitignore. Ini kesalahan paling umum saat bekerja dalam team.


Initial Migrations (Ikuti dan Praktekkan)

Ini yang perlu kita lakukan di project yang kita gunakan sejak awal, beserta penjelasannya:

1. Membuat model di books/models.py

Saat ini file kita masih belum terisi. Mari tambahkan sesuatu untuk di-migrate. Contohnya:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    isbn = models.CharField(max_length=13, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

2. Makemigrations

1
python manage.py makemigrations

Perintah tersebut akan memindai / scan semua app di INSTALLED_APPS, melakukan deteksi perubahan pada model sejak state paling terakhir, dan membuat file migration baru. Output-nya kira-kira seperti ini:

1
2
3
Migrations for 'books':
  books/migrations/0001_initial.py
    + Create model Book

Kita juga bisa menargetkan app yang spesifik:

1
python manage.py makemigrations books

3. Lihat SQL yang akan dijalanin (opsional tapi edukatif)

1
python manage.py sqlmigrate books 0001

Perintah tersebut menampilkan query SQL yang akan dieksekusi Django. Sangat bagus untuk memahami apa yang terjadi di balik layar

4. Apply migrations

1
python manage.py migrate

Perintah tersebut menerapkan semua migration yang masih pending, baik yang bawaan Django (untuk auth, admin, dll.) maupun yang kita buat. Setelah perintah ini berjalan, db.sqlite3 akan dibuat (atau diupdate) lengkap dengan semua tabelnya.

5. Verifikasi

1
python manage.py showmigrations

Ini akan menampilkan semua migration dan statusnya ([X] jika sudah diapply, [ ] jika belum). Project yang sudah menerapkan semua migrationnya akan menampilkan semuanya sebagai [X].


Cheat Sheet

PerintahFungsi
makemigrationsGenerate file migration dari perubahan model
makemigrations <appname>Generate hanya untuk app tertentu
migrateMenerapkan semua pending migration ke DB
migrate <appname> <num>Migrate ke versi spesifik (untuk rollback)
sqlmigrate <app> <num>Preview SQL tanpa langsung dieksekusi
showmigrationsTampilkan semua migration dan status penerapan-nya

Kesalahan Yang Sering Terjadi

  1. Menjalankan migrate tanpa makemigrations terlebih dahulu. Migrate hanya apply file yang sudah ada, migrate tidak secara otomatis mendeteksi jika ada model baru. Kedua perintah ini perlu dijalankan berurutan.

  2. Menghapus file migration. Jika kita menghapus file migration yang sudah pernah diapply, Django kehilangan rekam jejak dari state database. Jangan pernah hapus migration yang sudah diapply. Jika ingin melakukan revert, buat migration baru yang dikembalikan perubahannya.

  3. Tidak melakukan commit file migration ke git. Teman satu team kita tidak bisa melakukan sinkronisasi schema database mereka.

  4. Melakukan edit file migration secara manual tanpa memahami dependency graph-nya – Migration di Django membentuk rantai dependency. Mengedit file migration secara manual dapat memutus rantai itu. Jika perlu melakukan adjustment, sebaiknya generate migration baru.

  5. Lupa menjalankan migrate setelah git pull – selalu jalanin migrate setelah pull dari git. Lebih baik lagi jika dijadikan sebagai bagian dari script deployment script.

Foto cover oleh creativemindsfactory dari Unsplash

Dibawah Lisensi CC BY-NC-SA 4.0
Dibangun dengan Hugo
Tema Stack dirancang oleh Jimmy