Settings and Multi-Environment Configuration
Introduction
config/settings.py controls almost every runtime behavior: debug mode, hosts, database, templates, and secrets. This chapter explains the most important settings for development, shows how to load values from .env, and splits configuration into base / development / production modules—the pattern teams use before deploying with Gunicorn and Nginx.
Prerequisites
- Project Structure and Settings Overview
hello-django/project from chapter 03- Virtual environment activated
Core Settings Explained
SECRET_KEY
Used for signing sessions, CSRF tokens, and password reset links.
SECRET_KEY = "django-insecure-..." # auto-generated by startproject| Environment | Rule |
|---|---|
| Development | Default insecure key is OK locally only |
| Production | Long random string from env var; never commit |
Generate a new key (example):
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"DEBUG
DEBUG = TrueDEBUG | Behavior |
|---|---|
True | Detailed error pages with traceback; static files served simply in dev |
False | Generic error pages; requires ALLOWED_HOSTS and proper logging |
Warning
Never Ship DEBUG=True
Public sites with DEBUG=True leak settings and code paths. Production must use DEBUG=False.
ALLOWED_HOSTS
ALLOWED_HOSTS = []When DEBUG=False, Django rejects requests whose Host header is not listed.
Examples:
ALLOWED_HOSTS = ["example.com", "www.example.com"]
ALLOWED_HOSTS = [".example.com"] # subdomainsWith DEBUG=True, empty list is allowed for localhost / 127.0.0.1.
INSTALLED_APPS and MIDDLEWARE
Already touched in earlier chapters. Adding a third-party package usually means:
pip install package- Add app string to
INSTALLED_APPS - Add middleware if docs require (order matters)
DATABASES
Default development config:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}MySQL production example (preview—full setup in ORM chapters):
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": os.environ.get("DB_PASSWORD", ""),
"HOST": "127.0.0.1",
"PORT": "3306",
"OPTIONS": {"charset": "utf8mb4"},
}
}Link: MySQL track.
TEMPLATES
DIRS— project-wide template foldersAPP_DIRS— findapp/templates/in each installed app
STATIC_URL and MEDIA (preview)
STATIC_URL = "static/"
# MEDIA_URL = "media/"
# MEDIA_ROOT = BASE_DIR / "media"MEDIA_* for user uploads—configured fully in chapter 16.
Internationalization
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = TrueUse TIME_ZONE = "Asia/Shanghai" (or your zone) when displaying local times—keep USE_TZ = True for aware datetimes.
Load Settings from Environment Variables
Install python-dotenv (development convenience):
pip install python-dotenvAdd to requirements.txt.
Create .env in project root (already in .gitignore):
DJANGO_SECRET_KEY=your-dev-secret-key-here
DJANGO_DEBUG=True
DATABASE_URL=sqlite:///db.sqlite3At the top of settings (before split refactor, or in base.py):
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv(BASE_DIR / ".env")
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"Code explanation:
load_dotenvreads.envintoos.environ- Production servers set env vars in systemd/Docker instead of files—same
os.environaccess
Tip
Fail Fast on Missing Secrets
Use os.environ["DJANGO_SECRET_KEY"] in production so misconfiguration crashes at startup, not silently with an insecure default.
Split Settings: base / development / production
Replace single config/settings.py with a package:
config/
├── settings/
│ ├── __init__.py
│ ├── base.py
│ ├── development.py
│ └── production.py
├── urls.py
├── wsgi.py
└── asgi.pyconfig/settings/base.py
Shared defaults:
config/settings/development.py
from .base import *
SECRET_KEY = "dev-only-insecure-key"
DEBUG = True
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}config/settings/production.py
config/settings/init.py
Empty or import development by default for local work:
from .development import *Point manage.py and wsgi at the right module
manage.py (development default):
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.development")config/wsgi.py (production):
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")Run with explicit module (without editing files):
DJANGO_SETTINGS_MODULE=config.settings.production python manage.py checkWindows PowerShell:
$env:DJANGO_SETTINGS_MODULE="config.settings.production"
python manage.py checkVerify Configuration
python manage.py check
python manage.py check --deploy--deploy warns about DEBUG, SECRET_KEY, ALLOWED_HOSTS, HTTPS settings—useful before production.
Settings Quick Reference
| Setting | Dev typical | Prod typical |
|---|---|---|
DEBUG | True | False |
SECRET_KEY | Local / .env | Strong env var |
ALLOWED_HOSTS | localhost, 127.0.0.1 | Your domain(s) |
DATABASES | SQLite file | MySQL/PostgreSQL |
| HTTPS | Optional | Nginx + TLS |
Common Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
DEBUG=True on VPS | Settings leak in browser | production.py with DEBUG=False |
Empty ALLOWED_HOSTS in prod | DisallowedHost | Add domain |
Committed .env | Secret leak | Rotate keys; use .gitignore |
Wrong DJANGO_SETTINGS_MODULE | Wrong DB or debug flag | Check manage.py, systemd Environment |
Editing base.py for one env | Prod/dev coupling | Override in development.py / production.py only |
Post-Chapter Checklist
- You can explain
SECRET_KEY,DEBUG,ALLOWED_HOSTS - You know default SQLite
DATABASESlayout - You created
.env(gitignored) or understand env vars - You understand base / development / production split (optional but recommended)
-
python manage.py checkpasses
FAQ
Keep single settings.py for learning?
Yes initially. Split when you deploy or feel if DEBUG branches piling up.
django-environ vs python-dotenv?
Both work. django-environ parses DATABASE_URL strings; python-dotenv is minimal—fine for this track.
Where set settings on Gunicorn?
Environment= or EnvironmentFile= in systemd; DJANGO_SETTINGS_MODULE=config.settings.production.
Change LANGUAGE_CODE to Chinese?
LANGUAGE_CODE = "zh-hans" — also translate UI strings with Django i18n (advanced).
Is SQLite enough for production?
For tiny low-traffic sites, maybe. Most production Django sites use MySQL or PostgreSQL.
Commit settings/production.py?
Yes—the file should contain no secrets, only os.environ lookups.