Belajar Django - Settings & Environments Management
Episode 16 of 27

Belajar Django - Settings & Environments Management

Mengelola konfigurasi antar environment dengan pola settings modular dan pydantic-settings/django-environ, mengamankan secrets lewat environment variables, serta menerapkan prinsip 12-factor app agar project siap dipindah antar environment tanpa mengubah kode.

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

Pendahuluan

Sampai episode 15, settings.py masih monolitik: SECRET_KEY, kredensial database, dan email ter-hardcode. Di development itu terasa nyaman — sampai kode yang sama harus jalan di staging dan produksi dengan konfigurasi berbeda. Di episode ini kita merombak pengelolaan settings: modular, berbasis environment variable, dan aman.

Mengapa topik ini penting? Ini adalah jantung 12-factor app — metodologi membangun aplikasi yang bisa dipindah antar environment tanpa mengubah kode. SECRET_KEY bocor di git sama berbahayanya dengan password database yang hardcode. Memisahkan konfigurasi dari kode adalah langkah pertama menuju deployment yang aman (episode 23).

Masalah dengan settings.py Monolitik

Satu file settings yang di-share semua environment memunculkan tiga masalah:

  1. Secrets bocorSECRET_KEY, password DB ikut ter-commit ke git.
  2. Nilai tidak cocokDEBUG=True untuk development tidak boleh menyala di produksi.
  3. Konteks hilang — siapa yang tahu konfigurasi itu untuk environment mana?

Solusinya: pindahkan nilai yang berubah antar environment ke environment variables, dan jadikan settings modular.

Pola Settings Modular

Struktur yang umum dipakai project Django production:

Struktur settings modular
devblog/
  settings/
    __init__.py      # memilih base sesuai env
    base.py          # pengaturan bersama semua env
    development.py   # DEBUG=True, toolbar, email console
    staging.py       # mirip produksi, data test
    production.py    # DEBUG=False, hardening

base.py berisi semua yang sama; file lain meng-import base dan menyesuaikan:

Pythondevblog/settings/development.py
from .base import *   # noqa: F403
 
DEBUG = True
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
 
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
 
INSTALLED_APPS += ["debug_toolbar"]   # noqa: F405
MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"]   # noqa: F405
Pythondevblog/settings/production.py
from .base import *   # noqa: F403
 
DEBUG = False
ALLOWED_HOSTS = ["devvnull.vercel.app"]
 
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Kunci __init__.py — ia memilih file mana yang di-load:

Pythondevblog/settings/__init__.py
import os
 
ENVIRONMENT = os.environ.get("DJANGO_ENVIRONMENT", "development")
 
if ENVIRONMENT == "production":
    from .production import *   # noqa: F401,F403
elif ENVIRONMENT == "staging":
    from .staging import *      # noqa: F401,F403
else:
    from .development import *  # noqa: F401,F403

Tip

Pilihan variabel DJANGO_ENVIRONMENT vs DJANGO_SETTINGS_MODULE adalah gaya masing-masing tim. Kunci konsistensinya: satu sumber kebenaran, mudah di-set di CI dan server. python manage.py check di pipeline produksi harus memakai DJANGO_ENVIRONMENT=production agar validasi benar-benar menguji settings produksi.

Mengelola Secrets: pydantic-settings

Sebagai ganti os.environ.get() mentah yang rawan typo, gunakan pydantic-settings (atau django-environ) untuk memuat, memvalidasi, dan memberi tipe environment variable:

Install pydantic-settings
pip install pydantic-settings
Pythondevblog/settings/env.py
from pathlib import Path
 
from pydantic_settings import BaseSettings, SettingsConfigDict
 
BASE_DIR = Path(__file__).resolve().parent.parent.parent
 
class Env(BaseSettings):
    SECRET_KEY: str
    DEBUG: bool = False
    ALLOWED_HOSTS: list[str] = []
 
    DB_NAME: str
    DB_USER: str
    DB_PASSWORD: str
    DB_HOST: str = "127.0.0.1"
    DB_PORT: int = 5432
 
    model_config = SettingsConfigDict(
        env_file=BASE_DIR / ".env",
        env_file_encoding="utf-8",
    )
 
env = Env()

Env() membaca .env (untuk development) dan environment variable sistem (untuk produksi/CI). Setiap field ter-validasi: DEBUG: bool menolak nilai "banana", ALLOWED_HOSTS: list[str] memparsing format list. Typo field langsung error saat startup, bukan di tengah jalan.

base.py lalu memakai env:

Pythondevblog/settings/base.py
from .env import BASE_DIR, env
 
SECRET_KEY = env.SECRET_KEY
DEBUG = env.DEBUG
ALLOWED_HOSTS = env.ALLOWED_HOSTS
 
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": env.DB_NAME,
        "USER": env.DB_USER,
        "PASSWORD": env.DB_PASSWORD,
        "HOST": env.DB_HOST,
        "PORT": env.DB_PORT,
    }
}

.env dan .env.example

Untuk development, simpan nilai di .env — file ini tidak boleh di-commit. Sebagai dokumentasi, commit .env.example:

.env.example
DJANGO_ENVIRONMENT=development
SECRET_KEY=change-me-in-production
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
DB_NAME=devblog
DB_USER=devblog
DB_PASSWORD=devblog
DB_HOST=127.0.0.1
DB_PORT=5432

Warning

.env harus masuk .gitignore — sudah kita mulai di episode 3. Periksa riwayat git secara berkala: kalau ada .env atau SECRET_KEY pernah ter-commit, asumsikan bocor dan rotasi sekarang. Secret yang terlanjur ter-commit ke history tidak hilang dengan menghapus file-nya — ia tetap bisa dibaca dari history.

12-Factor: Konfigurasi dari Environment

Prinsip 12-factor app yang paling relevan di episode ini (arsip resmi: 12factor.net):

PrinsipImplementasi Django
Config di environmentSemua nilai variabel lewat env, bukan hardcode di settings
Dev/prod paritasEnvironment sedekat mungkin: PostgreSQL di dev juga, bukan SQLite saja
Backing servicesDB/cache/broker sebagai layanan yang di-swap lewat env
Logs sebagai streamStructured logging ke stdout (episode 15)

Satu hal penting yang sering dilupakan: jangan membuat kondisi cabang di kode seperti if ENVIRONMENT == "production". Perbedaan antar environment dikelola di settings, bukan di logika aplikasi. Kode harus environment-agnostic.

Ganti manage.py

Karena settings kini modular, manage.py bisa disederhanakan agar mengambil env:

Pythonmanage.py
import os
import sys
 
def main():
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "devblog.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError("Couldn't import Django.") from exc
    execute_from_command_line(sys.argv)
 
if __name__ == "__main__":
    main()

Dengan __init__.py yang memilih environment, manage.py tidak perlu berubah — DJANGO_ENVIRONMENT yang menentukan segalanya.

Verifikasi

Uji settings per environment
DJANGO_ENVIRONMENT=development python manage.py check
DJANGO_ENVIRONMENT=production python manage.py check

Environment production harus gagal jika DEBUG=True atau ALLOWED_HOSTS kosong — justru itu yang kita inginkan: kesalahan konfigurasi terdeteksi dini, sebelum manage.py check --deploy di episode 18.

Penutup

Inti yang harus dibawa pulang:

  • Pisahkan base.py vs development.py/production.py; __init__.py memilih sesuai DJANGO_ENVIRONMENT.
  • pydantic-settings memuat dan memvalidasi environment variable — typo langsung terdeteksi.
  • Secrets (SECRET_KEY, password DB) hanya di environment/.env, tak pernah di kode.
  • .env.example di-commit sebagai dokumentasi; .env di-gitignore.
  • Ikuti 12-factor: konfigurasi dari environment, tanpa cabang logika per environment di kode.

Di episode 17 selanjutnya kita menangani aset: Static Files, Media & Storage — pengumpulan dengan collectstatic, penyajian dengan WhiteNoise, upload media ke S3-compatible, dan pengaturan storage backends untuk produksi. Sampai jumpa di episode 17!

Belajar Django - Settings & Environments Management | Belajar Django