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 are Python variables defined in a settings module that configure various aspects of your Django project. These settings control:
# 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'
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
# 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
# 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
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)
# 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
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
# 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 %}
# 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',
])
# 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
}
# 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,
},
},
}
# .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
}
# 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'
# 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,
}
# 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.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_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
# 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()
# 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()
# 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.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.
How Django Handles Requests
Understanding Django's request-response cycle is fundamental to building effective web applications. This comprehensive guide explores every step of how Django processes HTTP requests, from the initial URL resolution to the final response delivery.
Development Environment
A well-configured development environment is crucial for productive Django development. This section covers everything you need to set up a professional, efficient, and maintainable development workflow that scales from personal projects to enterprise applications.