Configuration strategy
coreintermediateRead secrets and per-environment values from environment variables (or a secret manager), never hard-code them; split settings by environment (base/development/production); and keep defaults safe — a missing override should fail closed, not fall back to something insecure.
Think of it as
Twelve-factor configuration treats settings.py as code (checked into git, identical everywhere) and treats the actual values — a database password, a secret key, which environment this is — as environment, injected at runtime. The moment a real secret is typed as a literal string in settings.py, it stops being config and becomes a leak waiting for the next `git log`.
What we're doing: Structure a settings package so shared config lives once and each environment overrides only what genuinely differs.
- 1
- Everything not overridden here — INSTALLED_APPS, MIDDLEWARE, TEMPLATES — is inherited unchanged from base.py, so there is exactly one place those are defined.
- 4
- DEBUG is hard-coded False here rather than read from an environment variable — a production file is exactly the place a safe value is worth pinning, not leaving to a possibly-missing env var.
Why this works: Splitting settings this way means a value that should never differ (INSTALLED_APPS) physically cannot drift between environments, while a value that must differ (DATABASES, ALLOWED_HOSTS) is forced to be explicitly set in each environment's own file — the file structure itself prevents the two kinds of mistake from being interchangeable.
Falling back to an insecure default when an environment variable is missing
Wrong
Better
What you see: A production deployment that forgot to set DJANGO_DEBUG runs with full debug tracebacks exposed to every visitor, discovered only after the fact.
Why: os.environ.get(key, default) silently returns default for a missing variable — there is no error to notice. Choosing the safe value ("False") as that default means a forgotten environment variable fails toward security; choosing the convenient value ("True", matching local development) means the exact same mistake fails toward exposure.
- base.py — INSTALLED_APPS, MIDDLEWARE — shared, never duplicated
- development.py / production.py — override only what genuinely differs
- environment variable / secret manager — SECRET_KEY, DB password — never a settings.py literal
Where each kind of configuration value should live
Together
Remember: Secrets and per-environment values come from the environment (or a secret manager), never a settings.py literal; a missing required value should raise, and a missing optional one should default to the SAFE choice, not the convenient one.
See also: settings · cookie and host security settings · settings py

