$ cat /posts/django-settings-configuration-and-environment-variables.md

Django Settings: Configuration and Environment Variables

drwxr-xr-x2026-01-225 min0 views
Django Settings: Configuration and Environment Variables

Django's settings module serves as the central configuration hub controlling every aspect of application behavior from database connections to security settings, installed applications to middleware configurations, and template engines to static file locations. Understanding settings architecture is fundamental to Django development as improper configuration causes application failures, security vulnerabilities, or performance issues impacting development productivity and production reliability. The settings.py file generated during project creation provides sensible defaults suitable for development but requires customization for production deployment including security hardening, database optimization, and environment-specific configurations. Managing settings across multiple environments like development, staging, and production presents challenges solved through environment variables, settings modules, or configuration management tools maintaining security while enabling flexible deployment workflows. Mastering Django settings enables building robust applications with proper security configurations, optimized database connections, efficient caching strategies, and environment-specific customizations supporting professional development practices from local development through production deployment and maintenance.

Core Django Settings

Django's settings.py contains numerous configuration options controlling framework behavior with several critical settings requiring understanding and proper configuration. The SECRET_KEY setting provides cryptographic signing for session cookies, password reset tokens, and other security features requiring a random, secret value never committed to version control. DEBUG controls whether detailed error pages display during exceptions enabling helpful troubleshooting in development but must be False in production preventing information disclosure. ALLOWED_HOSTS lists hostnames or IP addresses permitted to serve the application preventing HTTP Host header attacks and must include production domains. INSTALLED_APPS declares active Django applications and third-party packages enabling model discovery, template loading, and app-specific functionality. DATABASES configures database connections supporting multiple database engines including PostgreSQL, MySQL, SQLite, and Oracle with engine-specific options. MIDDLEWARE defines request/response processing layers executing in order for each request handling security, sessions, authentication, and cross-cutting concerns. Understanding these core settings enables proper Django configuration establishing security, functionality, and deployment requirements for web applications.

pythoncore_settings.py
# settings.py - Core Django settings

import os
from pathlib import Path

# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-!@#$-CHANGE-THIS-IN-PRODUCTION'
# Generate new secret key:
# python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

# Allowed hosts - required when DEBUG is False
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
# Production:
# ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com', '1.2.3.4']

# Application definition
INSTALLED_APPS = [
    # Django built-in apps
    'django.contrib.admin',        # Admin site
    'django.contrib.auth',         # Authentication framework
    'django.contrib.contenttypes', # Content types framework
    'django.contrib.sessions',     # Session framework
    'django.contrib.messages',     # Messaging framework
    'django.contrib.staticfiles',  # Static files management
    
    # Third-party apps
    'rest_framework',
    'corsheaders',
    
    # Your apps
    'blog',
    'accounts',
    'api',
]

# Middleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# Root URL configuration
ROOT_URLCONF = 'myproject.urls'

# Database configuration
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Password validation
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Environment-Based Configuration

Managing different configurations for development, staging, and production environments prevents hardcoding sensitive credentials while enabling environment-specific optimizations. Environment variables store configuration values outside source code keeping secrets secure and enabling deployment flexibility without code changes. The python-decouple or django-environ libraries parse environment variables with type conversion and default values simplifying configuration management. Creating separate settings files for each environment like settings_dev.py, settings_staging.py, and settings_prod.py enables environment-specific configurations while sharing common settings through base configurations. Environment variable approach stores settings in .env files locally and server environment variables in production maintaining security and flexibility. Docker deployments benefit from environment variables configured through docker-compose.yml or container orchestration platforms. Understanding environment-based configuration enables secure credential management, supports multiple deployment environments, facilitates team collaboration with personal configuration files, and follows twelve-factor app principles for modern application deployment.

pythonenvironment_config.py
# Using python-decouple for environment variables
# pip install python-decouple

# .env file (never commit to version control!)
# SECRET_KEY=your-secret-key-here
# DEBUG=True
# DATABASE_URL=postgresql://user:password@localhost:5432/dbname
# ALLOWED_HOSTS=localhost,127.0.0.1

# settings.py
from decouple import config, Csv
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# Read from environment variables
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())

# Database from environment
import dj_database_url
DATABASES = {
    'default': dj_database_url.config(
        default=config('DATABASE_URL')
    )
}

# Email configuration
EMAIL_HOST = config('EMAIL_HOST', default='localhost')
EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)
EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=False, cast=bool)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')

# AWS credentials
AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID', default='')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY', default='')

# ===== Alternative: Split settings files =====

# settings/base.py - Common settings
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    # Common apps
]

# settings/development.py
from .base import *

DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']

# settings/production.py
from .base import *

DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'production_db',
        'USER': 'postgres_user',
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': 'db.production.com',
        'PORT': '5432',
    }
}

# Use specific settings:
# export DJANGO_SETTINGS_MODULE=myproject.settings.production
# python manage.py runserver --settings=myproject.settings.development

# .gitignore - Don't commit sensitive files
# .env
# *.env
# db.sqlite3
# /media/
# /staticfiles/

Database Configuration

Django supports multiple database backends through the DATABASES setting providing abstraction over different database engines while maintaining consistent ORM usage. SQLite serves as the default development database requiring no installation or configuration but lacks features needed for production like concurrent write access and advanced indexing. PostgreSQL represents Django's recommended production database offering excellent Django support, advanced features, JSON fields, and full-text search capabilities. MySQL provides another popular production option with widespread hosting support though requiring careful character set configuration for proper Unicode handling. Database configuration includes engine specification, database name, host, port, username, password, and engine-specific options like connection timeouts or SSL requirements. Multiple database configuration enables read replicas, database sharding, or separate databases for different apps using database routers. Connection pooling improves performance by reusing database connections reducing connection overhead for each request. Understanding database configuration enables proper development and production database setup, optimization for performance and scale, and implementation of advanced database architectures supporting high-traffic applications.

pythondatabase_settings.py
# Database configurations for different backends

# SQLite (Development)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# PostgreSQL (Production)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',  # Or '127.0.0.1' or 'db.hostname.com'
        'PORT': '5432',
        'CONN_MAX_AGE': 600,  # Connection pooling (seconds)
        'OPTIONS': {
            'sslmode': 'require',  # Require SSL connection
        },
    }
}

# MySQL
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydatabase',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

# Multiple databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'main_db',
        'USER': 'postgres',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '5432',
    },
    'analytics': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'analytics_db',
        'USER': 'postgres',
        'PASSWORD': 'password',
        'HOST': 'analytics-server',
        'PORT': '5432',
    },
}

# Using database URL (with dj-database-url)
import dj_database_url

DATABASES = {
    'default': dj_database_url.parse(
        'postgresql://user:password@localhost:5432/dbname'
    )
}

# Or from environment variable
DATABASES = {
    'default': dj_database_url.config(
        default='sqlite:///db.sqlite3',
        conn_max_age=600
    )
}

# Database router for multiple databases
# database_router.py
class AnalyticsRouter:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'analytics':
            return 'analytics'
        return 'default'
    
    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'analytics':
            return 'analytics'
        return 'default'

# settings.py
DATABASE_ROUTERS = ['myproject.database_router.AnalyticsRouter']

Security Settings

Django provides numerous security settings protecting applications from common web vulnerabilities when properly configured. SECRET_KEY must be randomly generated, kept secret, and different per environment as it cryptographically signs session data and security tokens. DEBUG must be False in production as True exposes sensitive information including stack traces, settings variables, and query details to attackers. ALLOWED_HOSTS prevents HTTP Host header attacks by validating the Host header against configured allowed hostnames. SECURE_SSL_REDIRECT forces HTTPS by redirecting all HTTP requests improving security and SEO. SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE ensure cookies transmit only over HTTPS preventing interception. SECURE_HSTS_SECONDS enables HTTP Strict Transport Security instructing browsers to always use HTTPS. X_FRAME_OPTIONS prevents clickjacking by controlling iframe embedding. SECURE_CONTENT_TYPE_NOSNIFF prevents MIME-sniffing attacks. Understanding security settings enables hardening Django applications against attacks, passing security audits, meeting compliance requirements, and protecting user data through defense-in-depth security strategies implementing multiple protective layers.

pythonsecurity_settings.py
# Security settings for production

# Secret key (generate unique, never share)
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
    raise ValueError('SECRET_KEY environment variable must be set')

# Debug - MUST be False in production
DEBUG = False

# Allowed hosts - whitelist of allowed hostnames
ALLOWED_HOSTS = [
    'yourdomain.com',
    'www.yourdomain.com',
    '1.2.3.4',  # IP address
]

# HTTPS/SSL settings
SECURE_SSL_REDIRECT = True  # Redirect HTTP to HTTPS
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')  # For proxies

# Cookie security
SESSION_COOKIE_SECURE = True  # Send session cookie only over HTTPS
CSRF_COOKIE_SECURE = True  # Send CSRF cookie only over HTTPS
SECURE_BROWSER_XSS_FILTER = True  # Enable browser XSS protection

# HSTS (HTTP Strict Transport Security)
SECURE_HSTS_SECONDS = 31536000  # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

# Content Security Policy
SECURE_CONTENT_TYPE_NOSNIFF = True  # Prevent MIME sniffing
X_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking
# Or: X_FRAME_OPTIONS = 'SAMEORIGIN'

# Password validation
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 8,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Session settings
SESSION_COOKIE_HTTPONLY = True  # Prevent JavaScript access to session cookie
SESSION_COOKIE_AGE = 1209600  # 2 weeks in seconds
SESSION_SAVE_EVERY_REQUEST = False
SESSION_COOKIE_NAME = 'sessionid'

# CSRF settings
CSRF_COOKIE_HTTPONLY = True
CSRF_USE_SESSIONS = True  # Store CSRF token in session instead of cookie
CSRF_COOKIE_AGE = 31449600  # 1 year

# Security middleware (should be enabled)
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',  # Keep at top
    # Other middleware
]

# Disable browsable API in DRF (production)
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
}

# Admin URL obfuscation
# Instead of /admin/, use random URL:
# path('secret-admin-url-xyz/', admin.site.urls),

# Run security check
# python manage.py check --deploy

Logging Configuration

Django's logging configuration provides detailed application monitoring, error tracking, and debugging capabilities through Python's logging framework. Logging configuration defines handlers determining where log messages go such as console, files, or external services, formatters controlling message format, filters selecting which messages to process, and loggers capturing messages from different application components. Common logging strategies include console output during development for immediate feedback, file logging in production for persistent records, and integration with monitoring services like Sentry for error tracking and alerting. Log levels including DEBUG, INFO, WARNING, ERROR, and CRITICAL enable filtering messages by severity with production typically logging WARNING and above avoiding noise from informational messages. Understanding logging enables troubleshooting production issues through log analysis, monitoring application health through metrics and error rates, tracking user behavior and performance, and maintaining audit trails for security and compliance requirements supporting professional application operations and maintenance.

pythonlogging_settings.py
# Logging configuration

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'WARNING',
            'class': 'logging.FileHandler',
            'filename': BASE_DIR / 'logs' / 'django.log',
            'formatter': 'verbose',
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins', 'file'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myapp': {
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}

# Using logging in views
import logging

logger = logging.getLogger(__name__)

def my_view(request):
    logger.debug('Debug message')
    logger.info('Processing request')
    logger.warning('Something might be wrong')
    logger.error('Error occurred')
    logger.critical('Critical system error')
    
    try:
        # Some operation
        result = process_data()
    except Exception as e:
        logger.exception('Unexpected error: %s', e)
        raise
    
    return HttpResponse('Success')

# Integration with Sentry
# pip install sentry-sdk

import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn="your-sentry-dsn",
    integrations=[DjangoIntegration()],
    traces_sample_rate=1.0,
    send_default_pii=True,
    environment="production",
)

Settings Best Practices

Effective settings management follows established patterns ensuring security, maintainability, and deployment flexibility across environments. Never commit SECRET_KEY or sensitive credentials to version control using environment variables or secret management services instead protecting confidential information. Use environment-based configuration separating development, staging, and production settings enabling appropriate configurations per environment without code changes. Set DEBUG to False in production preventing information disclosure that aids attackers while maintaining detailed logging for troubleshooting. Configure allowed hosts restrictively listing only legitimate domains and IP addresses preventing HTTP Host header attacks. Implement comprehensive security settings including HTTPS enforcement, secure cookies, HSTS headers, and content security policies protecting users and data. Use connection pooling for databases improving performance by reusing connections reducing overhead for each request. Document custom settings explaining their purpose and valid values aiding team members and future maintenance. Regularly review settings against Django's security checklist running python manage.py check --deploy identifying security issues before production. These practices ensure secure, reliable Django configurations supporting professional development workflows from local development through production deployment and ongoing operations.

$ cat /comments/ (0)

new_comment.sh

// Email hidden from public

>_

$ cat /comments/

// No comments found. Be the first!

[session] guest@{codershandbook}[timestamp] 2026

Navigation

Connect

Subscribe

// 2026 {Coders Handbook}. EOF.