Misconfigured settings cause most deployment failures and security incidents in Django apps.
settings.py is a plain Python module selected by the DJANGO_SETTINGS_MODULE environment variable (manage.py, wsgi.py and asgi.py set a default). Key settings:
DEBUG: detailed error pages; must beFalsein productionSECRET_KEY: signs sessions, password reset tokens and more; keep it secret and stableALLOWED_HOSTS: host names the site may serve; required whenDEBUG=FalseDATABASES,CACHES,INSTALLED_APPS,MIDDLEWARE,TEMPLATES,STORAGESTIME_ZONEandUSE_TZ=True(the default): store aware datetimes in UTC
Keep secrets and per-environment values out of the repository. The simplest robust approach reads them from environment variables:
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # crash early if missing
DEBUG = os.environ.get("DJANGO_DEBUG", "") == "1"Libraries like django-environ add helpers for parsing booleans, lists and database URLs. Some teams use split modules (settings/base.py, dev.py, prod.py) that import from a base; either way, production defaults should be safe.
In code, always read settings via from django.conf import settings, never by importing your settings module, so tests can override values with @override_settings and the right module is used.
python manage.py diffsettings shows what differs from Django's defaults, and python manage.py check --deploy lists insecure production settings.
Example
# mysite/settings.py (excerpt)
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # required
DEBUG = os.environ.get("DJANGO_DEBUG", "0") == "1" # safe default: off
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("POSTGRES_DB", "blog"),
"USER": os.environ.get("POSTGRES_USER", "blog"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD", ""),
"HOST": os.environ.get("POSTGRES_HOST", "localhost"),
"CONN_MAX_AGE": 60, # reuse connections
}
}
# anywhere else in the code:
from django.conf import settings
page_size = getattr(settings, "BLOG_PAGE_SIZE", 20)Remember
- DEBUG off, a secret SECRET_KEY and ALLOWED_HOSTS are mandatory in production
- Read secrets and per-environment values from environment variables
- Access settings via django.conf.settings
- check --deploy audits production settings
Watch out for
- Committing SECRET_KEY and DEBUG = True to the repository and deploying them.