Introduction and Foundations

Django Settings

Django settings are the configuration backbone of your Django project. They control everything from database connections to security features, middleware configuration, and application behavior. Understanding how to properly configure and manage settings is crucial for building robust Django applications.

Django Settings

Django settings are the configuration backbone of your Django project. They control everything from database connections to security features, middleware configuration, and application behavior. Understanding how to properly configure and manage settings is crucial for building robust Django applications.

The Basics

What Are Django Settings?

Django settings are Python variables defined in a settings module that configure various aspects of your Django project. These settings control:

  • Database configuration
  • Security settings
  • Middleware and installed apps
  • Static files and media handling
  • Internationalization and localization
  • Caching and session configuration
  • Email and logging settings

Settings Module Structure

# settings.py - Basic structure
import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'your-secret-key-here'

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

ALLOWED_HOSTS = []

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Your apps here
    'myapp',
]

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_URLCONF = 'myproject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'myproject.wsgi.application'

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

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

# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

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

Designating the Settings

DJANGO_SETTINGS_MODULE

Django uses the DJANGO_SETTINGS_MODULE environment variable to locate your settings module:

# Set the settings module
export DJANGO_SETTINGS_MODULE=myproject.settings

# Or for a specific environment
export DJANGO_SETTINGS_MODULE=myproject.settings.production

Command Line Settings

# Using --settings flag
python manage.py runserver --settings=myproject.settings.development

# Using --settings with other commands
python manage.py migrate --settings=myproject.settings.production
python manage.py collectstatic --settings=myproject.settings.production

Programmatic Settings Configuration

# In your Python code
import os
import django
from django.conf import settings

# Configure settings before using Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()

# Now you can use Django
from myapp.models import MyModel

Default Settings

Understanding Django's Default Settings

Django provides sensible defaults for most settings. You can view all default settings:

# View all default settings
from django.conf import global_settings
print(dir(global_settings))

# Check specific default values
print(global_settings.USE_TZ)  # True
print(global_settings.SESSION_COOKIE_AGE)  # 1209600 (2 weeks)

Common Default Settings

# These are some important defaults Django provides:

# Security
SECRET_KEY = None  # Must be set in your settings
DEBUG = False
ALLOWED_HOSTS = []

# Database
DATABASES = {}  # Must be configured

# Applications
INSTALLED_APPS = []

# Middleware
MIDDLEWARE = []

# Templates
TEMPLATES = []

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True  # Deprecated in Django 4.0+
USE_TZ = True

# Static files
STATIC_URL = None
STATIC_ROOT = None

# Sessions
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_COOKIE_AGE = 1209600  # 2 weeks
SESSION_COOKIE_NAME = 'sessionid'

# CSRF
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_AGE = 31449600  # 1 year

# File uploads
FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440  # 2.5 MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 2621440  # 2.5 MB

Using Settings in Python Code

Accessing Settings

from django.conf import settings

def my_view(request):
    # Access settings values
    if settings.DEBUG:
        print("Debug mode is enabled")
    
    # Use settings in logic
    max_file_size = settings.FILE_UPLOAD_MAX_MEMORY_SIZE
    
    # Check if setting exists
    if hasattr(settings, 'CUSTOM_SETTING'):
        custom_value = settings.CUSTOM_SETTING
    
    # Get setting with default
    api_timeout = getattr(settings, 'API_TIMEOUT', 30)
    
    return render(request, 'template.html', {
        'debug_mode': settings.DEBUG,
        'site_name': getattr(settings, 'SITE_NAME', 'My Site'),
    })

# In models
from django.conf import settings
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    avatar = models.ImageField(upload_to='avatars/')
    
    def get_avatar_url(self):
        if self.avatar:
            return f"{settings.MEDIA_URL}{self.avatar}"
        return f"{settings.STATIC_URL}images/default-avatar.png"

# In forms
from django import forms
from django.conf import settings

class ContactForm(forms.Form):
    message = forms.CharField(
        widget=forms.Textarea,
        max_length=getattr(settings, 'MAX_MESSAGE_LENGTH', 1000)
    )
    
    def clean_message(self):
        message = self.cleaned_data['message']
        min_length = getattr(settings, 'MIN_MESSAGE_LENGTH', 10)
        
        if len(message) < min_length:
            raise forms.ValidationError(
                f"Message must be at least {min_length} characters long."
            )
        
        return message

Settings in Templates

# Add to context processors (settings.py)
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'OPTIONS': {
            'context_processors': [
                # ... other processors
                'myproject.context_processors.settings_context',
            ],
        },
    },
]

# context_processors.py
from django.conf import settings

def settings_context(request):
    """Add selected settings to template context"""
    return {
        'DEBUG': settings.DEBUG,
        'SITE_NAME': getattr(settings, 'SITE_NAME', 'My Site'),
        'CONTACT_EMAIL': getattr(settings, 'CONTACT_EMAIL', ''),
        'GOOGLE_ANALYTICS_ID': getattr(settings, 'GOOGLE_ANALYTICS_ID', ''),
    }
<!-- In templates -->
{% if DEBUG %}
    <div class="debug-toolbar">Debug mode is active</div>
{% endif %}

<title>{{ SITE_NAME }} - Welcome</title>

{% if GOOGLE_ANALYTICS_ID %}
    <!-- Google Analytics code -->
    <script async src="https://www.googletagmanager.com/gtag/js?id={{ GOOGLE_ANALYTICS_ID }}"></script>
{% endif %}

Altering Settings at Runtime

Dynamic Settings Configuration

# settings.py - Environment-based configuration
import os
from pathlib import Path

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

# Environment-specific settings
ENVIRONMENT = os.getenv('DJANGO_ENVIRONMENT', 'development')

if ENVIRONMENT == 'production':
    DEBUG = False
    ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
    
    # Production database
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.getenv('DB_NAME'),
            'USER': os.getenv('DB_USER'),
            'PASSWORD': os.getenv('DB_PASSWORD'),
            'HOST': os.getenv('DB_HOST', 'localhost'),
            'PORT': os.getenv('DB_PORT', '5432'),
        }
    }
    
    # Production static files
    STATIC_ROOT = '/var/www/static/'
    MEDIA_ROOT = '/var/www/media/'
    
elif ENVIRONMENT == 'staging':
    DEBUG = True
    ALLOWED_HOSTS = ['staging.yourdomain.com']
    
    # Staging database
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': 'staging_db',
            'USER': 'staging_user',
            'PASSWORD': os.getenv('STAGING_DB_PASSWORD'),
            'HOST': 'localhost',
            'PORT': '5432',
        }
    }
    
else:  # development
    DEBUG = True
    ALLOWED_HOSTS = ['localhost', '127.0.0.1']
    
    # Development database
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }

# Feature flags
FEATURE_FLAGS = {
    'NEW_DASHBOARD': os.getenv('FEATURE_NEW_DASHBOARD', 'false').lower() == 'true',
    'BETA_FEATURES': os.getenv('FEATURE_BETA', 'false').lower() == 'true',
    'MAINTENANCE_MODE': os.getenv('MAINTENANCE_MODE', 'false').lower() == 'true',
}

# Dynamic middleware based on environment
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
]

if ENVIRONMENT == 'production':
    MIDDLEWARE.insert(0, 'whitenoise.middleware.WhiteNoiseMiddleware')

if FEATURE_FLAGS['MAINTENANCE_MODE']:
    MIDDLEWARE.insert(0, 'myproject.middleware.MaintenanceModeMiddleware')

MIDDLEWARE.extend([
    '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',
])

Runtime Settings Modification

# Modifying settings at runtime (use with caution)
from django.conf import settings

def configure_runtime_settings():
    """Modify settings at runtime - use sparingly"""
    
    # Check if settings are already configured
    if not settings.configured:
        settings.configure(
            DEBUG=True,
            DATABASES={
                'default': {
                    'ENGINE': 'django.db.backends.sqlite3',
                    'NAME': ':memory:',
                }
            },
            INSTALLED_APPS=[
                'django.contrib.auth',
                'django.contrib.contenttypes',
                'myapp',
            ],
        )
    
    # Modify existing settings (dangerous!)
    # settings.DEBUG = False  # This won't work - settings are read-only
    
    # Instead, use environment variables or configuration files

# Better approach: Configuration classes
class BaseConfig:
    DEBUG = False
    TESTING = False
    SECRET_KEY = os.getenv('SECRET_KEY')
    
    @classmethod
    def init_app(cls, app):
        pass

class DevelopmentConfig(BaseConfig):
    DEBUG = True
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': 'dev.db',
        }
    }

class ProductionConfig(BaseConfig):
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.getenv('DB_NAME'),
            'USER': os.getenv('DB_USER'),
            'PASSWORD': os.getenv('DB_PASSWORD'),
        }
    }

class TestingConfig(BaseConfig):
    TESTING = True
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': ':memory:',
        }
    }

# Configuration mapping
config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'testing': TestingConfig,
    'default': DevelopmentConfig
}

Security

Essential Security Settings

# settings.py - Security configuration

# Secret key - NEVER commit to version control
SECRET_KEY = os.getenv('SECRET_KEY')
if not SECRET_KEY:
    raise ValueError("SECRET_KEY environment variable is required")

# Debug - NEVER True in production
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'

# Allowed hosts - Restrict to your domains
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',') if os.getenv('ALLOWED_HOSTS') else []

# Security middleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    # ... other middleware
]

# HTTPS settings
if not DEBUG:
    SECURE_SSL_REDIRECT = True
    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    SECURE_HSTS_SECONDS = 31536000  # 1 year
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_PRELOAD = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SECURE_BROWSER_XSS_FILTER = True
    X_FRAME_OPTIONS = 'DENY'

# Session security
SESSION_COOKIE_SECURE = not DEBUG
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_AGE = 3600  # 1 hour

# CSRF protection
CSRF_COOKIE_SECURE = not DEBUG
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_TRUSTED_ORIGINS = ['https://yourdomain.com']

# Database security
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME'),
        'USER': os.getenv('DB_USER'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST', 'localhost'),
        'PORT': os.getenv('DB_PORT', '5432'),
        'OPTIONS': {
            'sslmode': 'require',
        },
    }
}

# File upload security
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB
FILE_UPLOAD_PERMISSIONS = 0o644

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

# Logging security events
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'security_file': {
            'level': 'WARNING',
            'class': 'logging.FileHandler',
            'filename': 'security.log',
        },
    },
    'loggers': {
        'django.security': {
            'handlers': ['security_file'],
            'level': 'WARNING',
            'propagate': True,
        },
    },
}

Environment Variables for Security

# .env file (never commit to version control)
SECRET_KEY=your-very-long-random-secret-key-here
DEBUG=False
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com

# Database
DB_NAME=myproject_prod
DB_USER=myproject_user
DB_PASSWORD=secure-database-password
DB_HOST=localhost
DB_PORT=5432

# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password

# Third-party services
AWS_ACCESS_KEY_ID=your-aws-access-key
AWS_SECRET_ACCESS_KEY=your-aws-secret-key
STRIPE_PUBLIC_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
# Load environment variables
import os
from pathlib import Path
from dotenv import load_dotenv

# Load .env file
load_dotenv()

# Or use django-environ
import environ

env = environ.Env(
    DEBUG=(bool, False),
    ALLOWED_HOSTS=(list, []),
)

# Read .env file
environ.Env.read_env(BASE_DIR / '.env')

# Use environment variables
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
ALLOWED_HOSTS = env('ALLOWED_HOSTS')

DATABASES = {
    'default': env.db()  # Parses DATABASE_URL
}

Available Settings

Core Django Settings

# Essential settings every Django project needs

# Project basics
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'your-secret-key'
DEBUG = False
ALLOWED_HOSTS = []

# Applications and middleware
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

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',
]

# URL configuration
ROOT_URLCONF = 'myproject.urls'

# Templates
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# WSGI/ASGI
WSGI_APPLICATION = 'myproject.wsgi.application'
ASGI_APPLICATION = 'myproject.asgi.application'

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'myproject',
        'USER': 'myproject_user',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

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

# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static']

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

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

Advanced Settings Categories

# Authentication and authorization
AUTH_USER_MODEL = 'accounts.User'  # Custom user model
LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = '/dashboard/'
LOGOUT_REDIRECT_URL = '/'

# Session configuration
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 1209600  # 2 weeks
SESSION_SAVE_EVERY_REQUEST = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

# Cache configuration
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        },
        'KEY_PREFIX': 'myproject',
        'TIMEOUT': 300,
    }
}

# Email configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com'
EMAIL_HOST_PASSWORD = 'your-password'
DEFAULT_FROM_EMAIL = 'MyProject <noreply@myproject.com>'
SERVER_EMAIL = 'server@myproject.com'

# File uploads
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB
FILE_UPLOAD_TEMP_DIR = '/tmp'
FILE_UPLOAD_PERMISSIONS = 0o644
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755

# Logging
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'file': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': 'django.log',
            'formatter': 'verbose',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'WARNING',
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False,
        },
        'myproject': {
            'handlers': ['file', 'console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}

# Celery (if using)
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE

# Third-party integrations
AWS_ACCESS_KEY_ID = 'your-access-key'
AWS_SECRET_ACCESS_KEY = 'your-secret-key'
AWS_STORAGE_BUCKET_NAME = 'your-bucket'
AWS_S3_REGION_NAME = 'us-east-1'

# API settings
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
}

Creating Your Own Settings

Custom Settings Best Practices

# settings.py - Custom settings organization

# Group related settings together
# ================================
# CUSTOM APPLICATION SETTINGS
# ================================

# Site configuration
SITE_NAME = 'My Awesome Project'
SITE_DESCRIPTION = 'A Django project that does amazing things'
SITE_KEYWORDS = 'django, python, web, development'
CONTACT_EMAIL = 'contact@myproject.com'
SUPPORT_EMAIL = 'support@myproject.com'

# Feature flags
FEATURES = {
    'ENABLE_REGISTRATION': True,
    'ENABLE_SOCIAL_LOGIN': True,
    'ENABLE_EMAIL_VERIFICATION': True,
    'ENABLE_TWO_FACTOR_AUTH': False,
    'ENABLE_API': True,
    'ENABLE_ADMIN_DASHBOARD': True,
}

# Business logic settings
MAX_UPLOAD_SIZE = 10 * 1024 * 1024  # 10MB
ALLOWED_FILE_TYPES = ['.jpg', '.jpeg', '.png', '.gif', '.pdf', '.doc', '.docx']
MAX_FILES_PER_UPLOAD = 5
DEFAULT_PAGINATION_SIZE = 25
MAX_PAGINATION_SIZE = 100

# API configuration
API_VERSION = 'v1'
API_RATE_LIMIT = '1000/hour'
API_THROTTLE_RATES = {
    'anon': '100/hour',
    'user': '1000/hour',
    'premium': '5000/hour',
}

# Notification settings
NOTIFICATION_SETTINGS = {
    'EMAIL_NOTIFICATIONS': True,
    'SMS_NOTIFICATIONS': False,
    'PUSH_NOTIFICATIONS': True,
    'DIGEST_FREQUENCY': 'weekly',  # daily, weekly, monthly
}

# Social media integration
SOCIAL_MEDIA = {
    'FACEBOOK_APP_ID': os.getenv('FACEBOOK_APP_ID'),
    'TWITTER_API_KEY': os.getenv('TWITTER_API_KEY'),
    'GOOGLE_CLIENT_ID': os.getenv('GOOGLE_CLIENT_ID'),
    'LINKEDIN_CLIENT_ID': os.getenv('LINKEDIN_CLIENT_ID'),
}

# Payment processing
PAYMENT_SETTINGS = {
    'STRIPE_PUBLIC_KEY': os.getenv('STRIPE_PUBLIC_KEY'),
    'STRIPE_SECRET_KEY': os.getenv('STRIPE_SECRET_KEY'),
    'PAYPAL_CLIENT_ID': os.getenv('PAYPAL_CLIENT_ID'),
    'CURRENCY': 'USD',
    'PAYMENT_SUCCESS_URL': '/payment/success/',
    'PAYMENT_CANCEL_URL': '/payment/cancel/',
}

# Analytics and tracking
ANALYTICS = {
    'GOOGLE_ANALYTICS_ID': os.getenv('GOOGLE_ANALYTICS_ID'),
    'MIXPANEL_TOKEN': os.getenv('MIXPANEL_TOKEN'),
    'HOTJAR_ID': os.getenv('HOTJAR_ID'),
    'ENABLE_TRACKING': not DEBUG,
}

# Content management
CONTENT_SETTINGS = {
    'ENABLE_COMMENTS': True,
    'MODERATE_COMMENTS': True,
    'ALLOW_ANONYMOUS_COMMENTS': False,
    'MAX_COMMENT_LENGTH': 1000,
    'ENABLE_MARKDOWN': True,
    'ENABLE_SYNTAX_HIGHLIGHTING': True,
}

# Search configuration
SEARCH_SETTINGS = {
    'ENABLE_SEARCH': True,
    'SEARCH_BACKEND': 'elasticsearch',  # elasticsearch, whoosh, solr
    'ELASTICSEARCH_URL': os.getenv('ELASTICSEARCH_URL', 'http://localhost:9200'),
    'SEARCH_RESULTS_PER_PAGE': 20,
    'ENABLE_AUTOCOMPLETE': True,
}

Settings Validation

# settings_validation.py
import os
from django.core.exceptions import ImproperlyConfigured

def validate_settings():
    """Validate custom settings"""
    
    # Required environment variables
    required_env_vars = [
        'SECRET_KEY',
        'DATABASE_URL',
    ]
    
    for var in required_env_vars:
        if not os.getenv(var):
            raise ImproperlyConfigured(f"Environment variable {var} is required")
    
    # Validate feature flags
    from django.conf import settings
    
    if hasattr(settings, 'FEATURES'):
        if settings.FEATURES.get('ENABLE_EMAIL_VERIFICATION') and not settings.EMAIL_HOST:
            raise ImproperlyConfigured(
                "EMAIL_HOST must be configured when email verification is enabled"
            )
    
    # Validate file upload settings
    if hasattr(settings, 'MAX_UPLOAD_SIZE'):
        if settings.MAX_UPLOAD_SIZE > 100 * 1024 * 1024:  # 100MB
            raise ImproperlyConfigured("MAX_UPLOAD_SIZE cannot exceed 100MB")
    
    # Validate payment settings
    if hasattr(settings, 'PAYMENT_SETTINGS'):
        payment = settings.PAYMENT_SETTINGS
        if not payment.get('STRIPE_SECRET_KEY') and not payment.get('PAYPAL_CLIENT_ID'):
            raise ImproperlyConfigured(
                "At least one payment provider must be configured"
            )

# In settings.py
validate_settings()

Settings Documentation

# settings_docs.py
"""
Custom Settings Documentation
============================

This module documents all custom settings used in the project.

Site Configuration:
------------------
SITE_NAME: str
    The display name of the site (default: 'My Awesome Project')

SITE_DESCRIPTION: str
    Brief description of the site for meta tags

CONTACT_EMAIL: str
    Primary contact email address

Feature Flags:
-------------
FEATURES: dict
    Dictionary of feature flags to enable/disable functionality
    
    ENABLE_REGISTRATION: bool
        Allow new user registration (default: True)
    
    ENABLE_SOCIAL_LOGIN: bool
        Enable social media login (default: True)
    
    ENABLE_API: bool
        Enable REST API endpoints (default: True)

Business Logic:
--------------
MAX_UPLOAD_SIZE: int
    Maximum file upload size in bytes (default: 10MB)

ALLOWED_FILE_TYPES: list
    List of allowed file extensions for uploads

API Configuration:
-----------------
API_RATE_LIMIT: str
    Default rate limit for API endpoints (default: '1000/hour')

API_THROTTLE_RATES: dict
    Rate limits for different user types

Payment Settings:
----------------
PAYMENT_SETTINGS: dict
    Payment provider configuration
    
    STRIPE_PUBLIC_KEY: str
        Stripe publishable key
    
    STRIPE_SECRET_KEY: str
        Stripe secret key (keep secure!)
    
    CURRENCY: str
        Default currency code (default: 'USD')

Usage Examples:
--------------
    from django.conf import settings
    
    # Check feature flags
    if settings.FEATURES['ENABLE_REGISTRATION']:
        # Show registration form
        pass
    
    # Use business logic settings
    max_size = settings.MAX_UPLOAD_SIZE
    
    # Access payment settings
    stripe_key = settings.PAYMENT_SETTINGS['STRIPE_PUBLIC_KEY']
"""

# Custom settings class for better organization
class CustomSettings:
    """Organized access to custom settings"""
    
    def __init__(self, settings_module):
        self.settings = settings_module
    
    @property
    def site_config(self):
        """Site configuration settings"""
        return {
            'name': getattr(self.settings, 'SITE_NAME', 'Django Site'),
            'description': getattr(self.settings, 'SITE_DESCRIPTION', ''),
            'contact_email': getattr(self.settings, 'CONTACT_EMAIL', ''),
        }
    
    @property
    def features(self):
        """Feature flags"""
        return getattr(self.settings, 'FEATURES', {})
    
    @property
    def upload_config(self):
        """File upload configuration"""
        return {
            'max_size': getattr(self.settings, 'MAX_UPLOAD_SIZE', 10 * 1024 * 1024),
            'allowed_types': getattr(self.settings, 'ALLOWED_FILE_TYPES', []),
            'max_files': getattr(self.settings, 'MAX_FILES_PER_UPLOAD', 5),
        }
    
    def is_feature_enabled(self, feature_name):
        """Check if a feature is enabled"""
        return self.features.get(feature_name, False)

# Usage in views
from django.conf import settings
custom_settings = CustomSettings(settings)

def my_view(request):
    if custom_settings.is_feature_enabled('ENABLE_REGISTRATION'):
        # Handle registration
        pass

Using Settings Without Setting DJANGO_SETTINGS_MODULE

Manual Settings Configuration

# standalone_django.py - Using Django without DJANGO_SETTINGS_MODULE
import django
from django.conf import settings

# Configure settings manually
settings.configure(
    DEBUG=True,
    SECRET_KEY='temporary-key-for-testing',
    DATABASES={
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': ':memory:',
        }
    },
    INSTALLED_APPS=[
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'myapp',
    ],
    USE_TZ=True,
)

# Setup Django
django.setup()

# Now you can use Django
from django.contrib.auth.models import User
from myapp.models import MyModel

def create_test_data():
    """Create test data without a full Django project"""
    user = User.objects.create_user('testuser', 'test@example.com', 'password')
    return user

if __name__ == '__main__':
    create_test_data()

Testing Configuration

# test_settings.py - Minimal settings for testing
import tempfile
from pathlib import Path

# Use temporary directory for testing
TEMP_DIR = Path(tempfile.mkdtemp())

# Minimal settings for testing
SETTINGS = {
    'DEBUG': True,
    'SECRET_KEY': 'test-secret-key-not-for-production',
    'DATABASES': {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': ':memory:',
        }
    },
    'INSTALLED_APPS': [
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'myapp',
    ],
    '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',
    ],
    'ROOT_URLCONF': 'myapp.urls',
    'TEMPLATES': [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [TEMP_DIR / 'templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ],
    'STATIC_URL': '/static/',
    'STATIC_ROOT': TEMP_DIR / 'static',
    'MEDIA_URL': '/media/',
    'MEDIA_ROOT': TEMP_DIR / 'media',
    'USE_TZ': True,
    'DEFAULT_AUTO_FIELD': 'django.db.models.BigAutoField',
}

# Configure Django
from django.conf import settings
import django

if not settings.configured:
    settings.configure(**SETTINGS)
    django.setup()

Script Configuration

# django_script.py - Standalone Django script
#!/usr/bin/env python
"""
Standalone Django script that doesn't require DJANGO_SETTINGS_MODULE
"""
import os
import sys
import django
from django.conf import settings

def configure_django():
    """Configure Django for standalone use"""
    
    # Basic configuration
    config = {
        'DEBUG': True,
        'SECRET_KEY': 'script-secret-key',
        'DATABASES': {
            'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': 'script_db.sqlite3',
            }
        },
        'INSTALLED_APPS': [
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'myapp',
        ],
        'USE_TZ': True,
    }
    
    # Configure settings if not already configured
    if not settings.configured:
        settings.configure(**config)
        django.setup()

def main():
    """Main script function"""
    configure_django()
    
    # Now you can use Django models and ORM
    from django.contrib.auth.models import User
    from myapp.models import MyModel
    
    # Create database tables
    from django.core.management import execute_from_command_line
    execute_from_command_line(['manage.py', 'migrate', '--run-syncdb'])
    
    # Your script logic here
    users = User.objects.all()
    print(f"Found {users.count()} users")
    
    # Create some data
    if not User.objects.filter(username='admin').exists():
        User.objects.create_superuser('admin', 'admin@example.com', 'password')
        print("Created admin user")

if __name__ == '__main__':
    main()

Dynamic Settings Loading

# dynamic_settings.py - Load settings from various sources
import os
import json
import yaml
from django.conf import settings
import django

class DynamicSettingsLoader:
    """Load Django settings from various sources"""
    
    def __init__(self):
        self.config = {}
    
    def load_from_file(self, file_path):
        """Load settings from JSON or YAML file"""
        if file_path.endswith('.json'):
            with open(file_path, 'r') as f:
                self.config.update(json.load(f))
        elif file_path.endswith(('.yml', '.yaml')):
            with open(file_path, 'r') as f:
                self.config.update(yaml.safe_load(f))
        else:
            raise ValueError("Unsupported file format")
    
    def load_from_env(self, prefix='DJANGO_'):
        """Load settings from environment variables"""
        for key, value in os.environ.items():
            if key.startswith(prefix):
                setting_name = key[len(prefix):]
                
                # Try to convert to appropriate type
                if value.lower() in ('true', 'false'):
                    value = value.lower() == 'true'
                elif value.isdigit():
                    value = int(value)
                elif ',' in value:
                    value = [item.strip() for item in value.split(',')]
                
                self.config[setting_name] = value
    
    def load_from_dict(self, config_dict):
        """Load settings from dictionary"""
        self.config.update(config_dict)
    
    def configure_django(self):
        """Configure Django with loaded settings"""
        if not settings.configured:
            settings.configure(**self.config)
            django.setup()

# Usage example
def setup_django_from_config():
    """Setup Django from multiple configuration sources"""
    loader = DynamicSettingsLoader()
    
    # Load base configuration
    base_config = {
        'DEBUG': True,
        'SECRET_KEY': 'default-secret-key',
        'DATABASES': {
            'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': 'default.db',
            }
        },
        'INSTALLED_APPS': [
            'django.contrib.auth',
            'django.contrib.contenttypes',
        ],
        'USE_TZ': True,
    }
    loader.load_from_dict(base_config)
    
    # Override with file configuration if exists
    config_file = os.getenv('DJANGO_CONFIG_FILE')
    if config_file and os.path.exists(config_file):
        loader.load_from_file(config_file)
    
    # Override with environment variables
    loader.load_from_env()
    
    # Configure Django
    loader.configure_django()

if __name__ == '__main__':
    setup_django_from_config()
    
    # Now Django is configured and ready to use
    from django.contrib.auth.models import User
    print("Django configured successfully!")

Django settings provide the foundation for configuring your application's behavior, security, and integrations. Understanding how to properly structure, secure, and manage settings is essential for building maintainable Django applications that can adapt to different environments and requirements.