Django cookbook · Beginner
Configure settings from environment variables
Keep secrets and per-environment values out of settings.py and fail fast when something required is missing.
Approach
Read configuration from environment variables in one place, with explicit types and defaults only for safe values. Missing secrets raise at startup instead of silently using a development value in production.
Solution
# settings.py
import os
from pathlib import Path
from django.core.exceptions import ImproperlyConfigured
BASE_DIR = Path(__file__).resolve().parent.parent
def env(name: str, default: str | None = None) -> str:
value = os.environ.get(name, default)
if value is None:
raise ImproperlyConfigured(f"Set the {name} environment variable")
return value
def env_bool(name: str, default: bool = False) -> bool:
return env(name, str(default)).lower() in {"1", "true", "yes", "on"}
def env_list(name: str, default: str = "") -> list[str]:
return [item.strip() for item in env(name, default).split(",") if item.strip()]
SECRET_KEY = env("DJANGO_SECRET_KEY") # required, no default
DEBUG = env_bool("DJANGO_DEBUG")
ALLOWED_HOSTS = env_list("DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1")
CSRF_TRUSTED_ORIGINS = env_list("DJANGO_CSRF_TRUSTED_ORIGINS")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": env("POSTGRES_DB", "app"),
"USER": env("POSTGRES_USER", "app"),
"PASSWORD": env("POSTGRES_PASSWORD"),
"HOST": env("POSTGRES_HOST", "localhost"),
"PORT": env("POSTGRES_PORT", "5432"),
"CONN_MAX_AGE": 60,
"CONN_HEALTH_CHECKS": True,
}
}
Pitfalls
- Defaulting
SECRET_KEYorDEBUG=True"for convenience"; a forgotten variable then ships insecure settings. - Parsing booleans with
bool(os.environ["DEBUG"]), which isTruefor the string "False". - Committing
.envfiles with real secrets.
Variations
- Use
django-environorpydantic-settingsfor the same pattern with URL parsing (DATABASE_URL). - Run
python manage.py check --deployin CI with production-like variables.
Further reading: Django settings
Reference: https://docs.djangoproject.com/en/6.0/topics/settings/
More Django recipes
- Add a required column without downtime
- Add full-text search with PostgreSQL
- Add health checks and structured logging
- Avoid N+1 queries with select_related and prefetch_related
- Cache expensive queries and invalidate on change
- Call external APIs concurrently in async views
- Enforce rules with database constraints
- Harden security settings, including a Content Security Policy