Proper environment management is crucial for Django applications. This comprehensive guide covers setting up and managing different environments, ensuring smooth transitions from development to production while maintaining security and performance.
Local Development
Staging
Production
myproject/
├── config/
│ ├── settings/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── local.py
│ │ ├── staging.py
│ │ └── production.py
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── requirements/
│ ├── base.txt
│ ├── local.txt
│ ├── staging.txt
│ └── production.txt
├── deploy/
│ ├── docker/
│ ├── nginx/
│ └── scripts/
├── .env.example
├── .env.local
├── .env.staging
└── .env.production
config/settings/base.py:
import os
from pathlib import Path
from decouple import config, Csv
# Build paths
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Core Django settings
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='', cast=Csv())
# Application definition
DJANGO_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
THIRD_PARTY_APPS = [
'rest_framework',
'corsheaders',
]
LOCAL_APPS = [
'accounts',
'blog',
'api',
]
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'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 = 'config.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 = 'config.wsgi.application'
ASGI_APPLICATION = 'config.asgi.application'
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = 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'
# Email configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = config('EMAIL_HOST', default='localhost')
EMAIL_PORT = config('EMAIL_PORT', default=587, cast=int)
EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', default='noreply@example.com')
# 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': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
},
'root': {
'handlers': ['console'],
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
},
}
config/settings/local.py:
from .base import *
# Debug mode
DEBUG = True
# Allowed hosts
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0', '.ngrok.io']
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Alternative: PostgreSQL for local development
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.postgresql',
# 'NAME': config('DB_NAME', default='myproject_local'),
# 'USER': config('DB_USER', default='postgres'),
# 'PASSWORD': config('DB_PASSWORD', default=''),
# 'HOST': config('DB_HOST', default='localhost'),
# 'PORT': config('DB_PORT', default='5432'),
# }
# }
# Development-specific apps
INSTALLED_APPS += [
'debug_toolbar',
'django_extensions',
'django_browser_reload',
]
# Development middleware
MIDDLEWARE += [
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django_browser_reload.middleware.BrowserReloadMiddleware',
]
# Debug toolbar configuration
DEBUG_TOOLBAR_CONFIG = {
'SHOW_TOOLBAR_CALLBACK': lambda request: True,
'SHOW_COLLAPSED': True,
'INTERCEPT_REDIRECTS': False,
}
# Internal IPs for debug toolbar
INTERNAL_IPS = [
'127.0.0.1',
'localhost',
]
# Email backend for development
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Cache (dummy cache for development)
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
# CORS settings for development
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
# Static files (development)
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
# Media files (development)
MEDIA_ROOT = BASE_DIR / 'media'
# Logging (development)
LOGGING['loggers']['django']['level'] = 'DEBUG'
LOGGING['loggers']['myproject'] = {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
}
# Development-specific settings
SHELL_PLUS_PRINT_SQL = True
SHELL_PLUS_PRINT_SQL_TRUNCATE = 1000
# File upload settings (relaxed for development)
FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 10MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 10MB
.env.local:
# Django settings
SECRET_KEY=local-development-secret-key-not-for-production
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
# Database
DATABASE_URL=sqlite:///db.sqlite3
# DATABASE_URL=postgresql://postgres:password@localhost:5432/myproject_local
# Email (development)
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
EMAIL_HOST=localhost
EMAIL_PORT=1025
# Cache
CACHE_URL=dummy://
# External services (development)
REDIS_URL=redis://localhost:6379/0
CELERY_BROKER_URL=redis://localhost:6379/0
# API keys (development/testing values)
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
# Feature flags
FEATURE_NEW_DASHBOARD=True
FEATURE_BETA_FEATURES=True
Setup Script (scripts/setup_local.sh):
#!/bin/bash
set -e
echo "🚀 Setting up local development environment..."
# Create virtual environment
if [ ! -d "venv" ]; then
echo "📦 Creating virtual environment..."
python -m venv venv
fi
# Activate virtual environment
source venv/bin/activate
# Upgrade pip
echo "⬆️ Upgrading pip..."
pip install --upgrade pip
# Install requirements
echo "📋 Installing requirements..."
pip install -r requirements/local.txt
# Copy environment file
if [ ! -f ".env" ]; then
echo "🔧 Creating .env file..."
cp .env.local .env
fi
# Create logs directory
mkdir -p logs
# Run migrations
echo "🗄️ Running migrations..."
python manage.py migrate
# Create superuser if it doesn't exist
echo "👤 Creating superuser..."
python manage.py shell -c "
from django.contrib.auth import get_user_model
User = get_user_model()
if not User.objects.filter(username='admin').exists():
User.objects.create_superuser('admin', 'admin@example.com', 'admin123')
print('Superuser created: admin/admin123')
else:
print('Superuser already exists')
"
# Load sample data
echo "📊 Loading sample data..."
python manage.py loaddata fixtures/sample_data.json
echo "✅ Local development environment setup complete!"
echo "💡 Run 'python manage.py runserver' to start the development server"
config/settings/staging.py:
from .base import *
import dj_database_url
# Debug mode (can be True for staging to help with debugging)
DEBUG = config('DEBUG', default=False, cast=bool)
# Allowed hosts
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
# Database
DATABASES = {
'default': dj_database_url.config(
default=config('DATABASE_URL')
)
}
# Security settings (less strict than production)
SECURE_SSL_REDIRECT = config('SECURE_SSL_REDIRECT', default=True, cast=bool)
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = config('SESSION_COOKIE_SECURE', default=True, cast=bool)
CSRF_COOKIE_SECURE = config('CSRF_COOKIE_SECURE', default=True, cast=bool)
# Static files
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Cache
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': config('REDIS_URL'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# Logging
LOGGING['handlers']['file'] = {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/staging.log',
'maxBytes': 1024*1024*10, # 10MB
'backupCount': 5,
'formatter': 'verbose',
}
LOGGING['loggers']['django']['handlers'] = ['console', 'file']
LOGGING['loggers']['myproject'] = {
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': False,
}
# Error reporting
ADMINS = [
('Staging Admin', config('ADMIN_EMAIL', default='staging@example.com')),
]
# Staging-specific apps (for testing)
INSTALLED_APPS += [
'django_extensions', # Useful for staging debugging
]
# Performance monitoring (staging)
if config('ENABLE_SILK', default=False, cast=bool):
INSTALLED_APPS += ['silk']
MIDDLEWARE += ['silk.middleware.SilkyMiddleware']
.env.staging:
# Django settings
SECRET_KEY=staging-secret-key-different-from-production
DEBUG=False
ALLOWED_HOSTS=staging.example.com
# Database
DATABASE_URL=postgresql://user:password@staging-db:5432/myproject_staging
# Email
EMAIL_HOST=smtp.mailgun.org
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=staging@mg.example.com
EMAIL_HOST_PASSWORD=staging-email-password
# Cache
REDIS_URL=redis://staging-redis:6379/0
# External services (staging/testing)
STRIPE_PUBLISHABLE_KEY=pk_test_staging_...
STRIPE_SECRET_KEY=sk_test_staging_...
AWS_ACCESS_KEY_ID=staging_access_key
AWS_SECRET_ACCESS_KEY=staging_secret_key
AWS_STORAGE_BUCKET_NAME=myproject-staging-media
# Monitoring
SENTRY_DSN=https://staging-sentry-dsn@sentry.io/project
# Feature flags (staging can test new features)
FEATURE_NEW_DASHBOARD=True
FEATURE_BETA_FEATURES=True
# Performance monitoring
ENABLE_SILK=True
Docker Compose for Staging:
# docker-compose.staging.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DJANGO_SETTINGS_MODULE=config.settings.staging
env_file:
- .env.staging
depends_on:
- db
- redis
volumes:
- ./logs:/var/log/django
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 2
db:
image: postgres:15
environment:
POSTGRES_DB: myproject_staging
POSTGRES_USER: postgres
POSTGRES_PASSWORD: staging_db_password
volumes:
- postgres_staging_data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/staging.conf:/etc/nginx/conf.d/default.conf
- ./staticfiles:/var/www/static
depends_on:
- web
volumes:
postgres_staging_data:
config/settings/production.py:
from .base import *
import dj_database_url
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.redis import RedisIntegration
# Security
DEBUG = False
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
# Database
DATABASES = {
'default': dj_database_url.config(
default=config('DATABASE_URL'),
conn_max_age=60,
conn_health_checks=True,
)
}
# Security settings
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_HSTS_SECONDS = 31536000
SECURE_REDIRECT_EXEMPT = []
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_AGE = 3600 # 1 hour
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY'
# Static files
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
WHITENOISE_USE_FINDERS = True
WHITENOISE_AUTOREFRESH = False
WHITENOISE_MAX_AGE = 31536000
# Media files (use cloud storage in production)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = config('AWS_S3_REGION_NAME', default='us-east-1')
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
AWS_DEFAULT_ACL = 'public-read'
# Cache
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': config('REDIS_URL'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'CONNECTION_POOL_KWARGS': {
'max_connections': 50,
'retry_on_timeout': True,
},
'COMPRESSOR': 'django_redis.compressors.zlib.ZlibCompressor',
'SERIALIZER': 'django_redis.serializers.json.JSONSerializer',
},
'KEY_PREFIX': 'myproject_prod',
'TIMEOUT': 300,
}
}
# Session engine
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# Logging
LOGGING['handlers']['file'] = {
'level': 'WARNING',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/production.log',
'maxBytes': 1024*1024*50, # 50MB
'backupCount': 10,
'formatter': 'verbose',
}
LOGGING['handlers']['error_file'] = {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/error.log',
'maxBytes': 1024*1024*50, # 50MB
'backupCount': 10,
'formatter': 'verbose',
}
LOGGING['loggers']['django'] = {
'handlers': ['file', 'error_file'],
'level': 'WARNING',
'propagate': False,
}
LOGGING['loggers']['myproject'] = {
'handlers': ['file', 'error_file'],
'level': 'INFO',
'propagate': False,
}
# Error reporting
ADMINS = [
('Production Admin', config('ADMIN_EMAIL')),
]
MANAGERS = ADMINS
# Sentry error tracking
sentry_sdk.init(
dsn=config('SENTRY_DSN'),
integrations=[
DjangoIntegration(
transaction_style='url',
middleware_spans=True,
signals_spans=True,
),
RedisIntegration(),
],
traces_sample_rate=0.1,
send_default_pii=False,
environment='production',
)
# Performance optimizations
CONN_MAX_AGE = 60
USE_TZ = True
# File upload restrictions
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB
DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
# Admin URL (security through obscurity)
ADMIN_URL = config('ADMIN_URL', default='admin/')
.env.production:
# Django settings
SECRET_KEY=super-secure-production-secret-key-change-this
DEBUG=False
ALLOWED_HOSTS=example.com,www.example.com
# Database
DATABASE_URL=postgresql://prod_user:secure_password@prod-db:5432/myproject_prod
# Email
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=apikey
EMAIL_HOST_PASSWORD=production-sendgrid-api-key
DEFAULT_FROM_EMAIL=noreply@example.com
# Cache
REDIS_URL=redis://prod-redis:6379/0
# AWS S3 (media files)
AWS_ACCESS_KEY_ID=production_access_key
AWS_SECRET_ACCESS_KEY=production_secret_key
AWS_STORAGE_BUCKET_NAME=myproject-production-media
AWS_S3_REGION_NAME=us-east-1
# External services (production)
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
# Monitoring
SENTRY_DSN=https://production-sentry-dsn@sentry.io/project
# Admin
ADMIN_EMAIL=admin@example.com
ADMIN_URL=secure-admin-url/
# Feature flags (production - conservative)
FEATURE_NEW_DASHBOARD=False
FEATURE_BETA_FEATURES=False
Docker Compose for Production:
# docker-compose.production.yml
version: '3.8'
services:
web:
build: .
environment:
- DJANGO_SETTINGS_MODULE=config.settings.production
env_file:
- .env.production
depends_on:
- db
- redis
volumes:
- ./logs:/var/log/django
- ./staticfiles:/app/staticfiles
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 4 --worker-class gevent
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_DB: myproject_prod
POSTGRES_USER: prod_user
POSTGRES_PASSWORD: secure_db_password
volumes:
- postgres_prod_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_prod_data:/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/nginx/production.conf:/etc/nginx/conf.d/default.conf
- ./deploy/ssl:/etc/nginx/ssl
- ./staticfiles:/var/www/static
depends_on:
- web
restart: unless-stopped
celery:
build: .
environment:
- DJANGO_SETTINGS_MODULE=config.settings.production
env_file:
- .env.production
depends_on:
- db
- redis
command: celery -A config worker -l info
restart: unless-stopped
celery-beat:
build: .
environment:
- DJANGO_SETTINGS_MODULE=config.settings.production
env_file:
- .env.production
depends_on:
- db
- redis
command: celery -A config beat -l info
restart: unless-stopped
volumes:
postgres_prod_data:
redis_prod_data:
scripts/switch_env.py:
#!/usr/bin/env python
"""
Environment switcher script
Usage: python scripts/switch_env.py local|staging|production
"""
import os
import sys
import shutil
from pathlib import Path
def switch_environment(env_name):
"""Switch to specified environment."""
valid_envs = ['local', 'staging', 'production']
if env_name not in valid_envs:
print(f"Invalid environment. Choose from: {', '.join(valid_envs)}")
return False
# Copy environment file
env_file = f'.env.{env_name}'
if not os.path.exists(env_file):
print(f"Environment file {env_file} not found")
return False
shutil.copy(env_file, '.env')
print(f"✓ Switched to {env_name} environment")
# Update manage.py settings module
settings_module = f'config.settings.{env_name}'
# Create or update .django_settings file
with open('.django_settings', 'w') as f:
f.write(settings_module)
print(f"✓ Django settings module: {settings_module}")
# Show current configuration
print("\nCurrent configuration:")
print(f"Environment: {env_name}")
print(f"Settings module: {settings_module}")
print(f"Environment file: {env_file}")
return True
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python scripts/switch_env.py <environment>")
print("Environments: local, staging, production")
sys.exit(1)
env_name = sys.argv[1]
success = switch_environment(env_name)
sys.exit(0 if success else 1)
scripts/validate_env.py:
#!/usr/bin/env python
"""
Environment validation script
"""
import os
import sys
import django
from pathlib import Path
def validate_environment():
"""Validate current environment configuration."""
# Load Django settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local')
django.setup()
from django.conf import settings
from django.core.management import call_command
print("🔍 Validating environment configuration...")
# Check required settings
required_settings = [
'SECRET_KEY',
'DATABASES',
'ALLOWED_HOSTS',
]
missing_settings = []
for setting in required_settings:
if not hasattr(settings, setting):
missing_settings.append(setting)
if missing_settings:
print(f"❌ Missing required settings: {', '.join(missing_settings)}")
return False
# Check database connectivity
try:
from django.db import connection
connection.ensure_connection()
print("✓ Database connection successful")
except Exception as e:
print(f"❌ Database connection failed: {e}")
return False
# Check cache connectivity
try:
from django.core.cache import cache
cache.set('test_key', 'test_value', 30)
if cache.get('test_key') == 'test_value':
print("✓ Cache connection successful")
else:
print("⚠️ Cache connection issue")
except Exception as e:
print(f"⚠️ Cache connection failed: {e}")
# Run Django system checks
try:
call_command('check', verbosity=0)
print("✓ Django system checks passed")
except Exception as e:
print(f"❌ Django system checks failed: {e}")
return False
# Environment-specific checks
if settings.DEBUG:
print("⚠️ DEBUG mode is enabled")
if 'production' in os.environ.get('DJANGO_SETTINGS_MODULE', ''):
print("❌ DEBUG should be False in production")
return False
if settings.SECRET_KEY == 'django-insecure-default-key':
print("❌ Using default SECRET_KEY")
return False
print("✅ Environment validation passed")
return True
if __name__ == '__main__':
success = validate_environment()
sys.exit(0 if success else 1)
scripts/blue_green_deploy.sh:
#!/bin/bash
set -e
ENVIRONMENT=${1:-staging}
NEW_VERSION=${2:-latest}
echo "🚀 Starting blue-green deployment for $ENVIRONMENT"
# Build new version
echo "📦 Building new version..."
docker build -t myproject:$NEW_VERSION .
# Deploy to green environment
echo "🟢 Deploying to green environment..."
docker-compose -f docker-compose.$ENVIRONMENT.yml -p myproject-green up -d
# Health check
echo "🏥 Running health checks..."
sleep 30
if curl -f http://localhost:8001/health/; then
echo "✅ Health check passed"
else
echo "❌ Health check failed"
docker-compose -f docker-compose.$ENVIRONMENT.yml -p myproject-green down
exit 1
fi
# Switch traffic
echo "🔄 Switching traffic..."
# Update load balancer configuration
# This would be specific to your load balancer (nginx, HAProxy, etc.)
# Stop old version
echo "🔴 Stopping blue environment..."
docker-compose -f docker-compose.$ENVIRONMENT.yml -p myproject-blue down
echo "✅ Blue-green deployment completed successfully"
scripts/rolling_deploy.sh:
#!/bin/bash
set -e
ENVIRONMENT=${1:-production}
REPLICAS=${2:-3}
echo "🔄 Starting rolling deployment for $ENVIRONMENT"
# Update one replica at a time
for i in $(seq 1 $REPLICAS); do
echo "📦 Updating replica $i/$REPLICAS..."
# Stop replica
docker-compose -f docker-compose.$ENVIRONMENT.yml stop web_$i
# Update and start replica
docker-compose -f docker-compose.$ENVIRONMENT.yml up -d web_$i
# Health check
sleep 15
if curl -f http://localhost:800$i/health/; then
echo "✅ Replica $i updated successfully"
else
echo "❌ Replica $i health check failed"
exit 1
fi
done
echo "✅ Rolling deployment completed successfully"
management/commands/health_check.py:
from django.core.management.base import BaseCommand
from django.db import connection
from django.core.cache import cache
import requests
class Command(BaseCommand):
help = 'Perform environment health check'
def handle(self, *args, **options):
checks = [
self.check_database,
self.check_cache,
self.check_external_services,
]
all_passed = True
for check in checks:
try:
check()
self.stdout.write(
self.style.SUCCESS(f'✓ {check.__name__} passed')
)
except Exception as e:
self.stdout.write(
self.style.ERROR(f'✗ {check.__name__} failed: {e}')
)
all_passed = False
if all_passed:
self.stdout.write(self.style.SUCCESS('All health checks passed'))
else:
self.stdout.write(self.style.ERROR('Some health checks failed'))
exit(1)
def check_database(self):
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
cursor.fetchone()
def check_cache(self):
cache.set('health_check', 'ok', 30)
if cache.get('health_check') != 'ok':
raise Exception('Cache not working')
def check_external_services(self):
# Check external API endpoints
response = requests.get('https://api.example.com/health', timeout=5)
response.raise_for_status()
Proper environment management ensures smooth development workflows, reliable deployments, and maintainable applications across different stages of the development lifecycle.
Django Project Settings
Django settings configuration is crucial for managing different environments, security, and application behavior. This comprehensive guide covers settings organization, environment management, and best practices for maintainable Django projects.
Running Django Development Server
Django's built-in development server is a lightweight, auto-reloading server designed for development and testing. This comprehensive guide covers everything you need to know about running, configuring, and optimizing the development server for productive Django development.