Deployment Preparation
Django application কে production এ deploy করার আগে proper preparation অত্যন্ত গুরুত্বপূর্ণ। এই গাইডে আমরা settings management, environment variables, static files, migrations, logging, এবং error reporting নিয়ে বিস্তারিত আলোচনা করব।
1. Settings Management (django-environ)
Install django-environ
bash
pip install django-environBasic Setup
python
# settings.py
import environ
import os
from pathlib import Path
# Build paths
BASE_DIR = Path(__file__).resolve().parent.parent
# Initialize environ
env = environ.Env(
# Default values এবং casting
DEBUG=(bool, False),
ALLOWED_HOSTS=(list, []),
DATABASE_URL=(str, 'sqlite:///db.sqlite3'),
)
# Read .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
# Use environment variables
DEBUG = env('DEBUG')
SECRET_KEY = env('SECRET_KEY')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
# Database
DATABASES = {
'default': env.db()
}.env File
bash
# .env (project root)
# Django settings
DEBUG=False
SECRET_KEY=your-super-secret-key-here-min-50-chars
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
# Redis
REDIS_URL=redis://localhost:6379/1
# AWS
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_STORAGE_BUCKET_NAME=your-bucket
# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
# Sentry
SENTRY_DSN=https://your-sentry-dsn.env.example Template
bash
# .env.example (commit to git)
# Django settings
DEBUG=True
SECRET_KEY=change-me-in-production
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
# Redis
REDIS_URL=redis://localhost:6379/1
# AWS (optional)
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_STORAGE_BUCKET_NAME=
# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
# Sentry (optional)
SENTRY_DSN=Advanced Configuration
python
# settings.py
import environ
env = environ.Env()
environ.Env.read_env()
# Multiple database support
DATABASES = {
'default': env.db('DATABASE_URL'),
'analytics': env.db('ANALYTICS_DATABASE_URL', default='sqlite:///analytics.db'),
}
# Cache configuration
CACHES = {
'default': env.cache('REDIS_URL'),
}
# Email configuration
EMAIL_CONFIG = env.email_url('EMAIL_URL', default='smtp://localhost:25')
vars().update(EMAIL_CONFIG)
# Search configuration
SEARCH_URL = env.search_url('SEARCH_URL', default='elasticsearch://localhost:9200')2. Environment Variables
Separate Settings Files
python
# settings/base.py
import environ
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env()
# Common settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# ...
]
# Templates, static files, etc.python
# 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',
}
}
# Development-specific settings
INSTALLED_APPS += [
'debug_toolbar',
'django_extensions',
]
MIDDLEWARE += [
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
INTERNAL_IPS = ['127.0.0.1']python
# settings/production.py
from .base import *
DEBUG = False
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
DATABASES = {
'default': env.db()
}
# Security settings
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Static files
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'Using Different Settings
bash
# Development
python manage.py runserver --settings=myproject.settings.development
# Production
python manage.py runserver --settings=myproject.settings.production
# Or set environment variable
export DJANGO_SETTINGS_MODULE=myproject.settings.production3. Production Settings
Complete Production Settings
python
# settings/production.py
import environ
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env()
environ.Env.read_env()
# Security
DEBUG = False
SECRET_KEY = env('SECRET_KEY')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
# Database
DATABASES = {
'default': env.db(),
}
# HTTPS/SSL
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# HSTS
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Cookies
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Strict'
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict'
# Security headers
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'
SECURE_REFERRER_POLICY = 'same-origin'
# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = env('EMAIL_HOST')
EMAIL_PORT = env.int('EMAIL_PORT', default=587)
EMAIL_USE_TLS = True
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL', default='noreply@example.com')
# Cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': env('REDIS_URL'),
}
}
# Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
# Admin
ADMIN_URL = env('ADMIN_URL', default='admin/')4. Static Files Collection
Static Files Configuration
python
# settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Static files finders
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]Collect Static Files
bash
# Collect all static files to STATIC_ROOT
python manage.py collectstatic --noinput
# Clear existing files before collecting
python manage.py collectstatic --clear --noinput
# Dry run (test without actually copying)
python manage.py collectstatic --dry-runWhiteNoise for Static Files
bash
pip install whitenoisepython
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # Add here
# Other middleware...
]
# WhiteNoise configuration
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Optional: Compression
WHITENOISE_COMPRESS_OFFLINE = TrueAWS S3 for Static Files
bash
pip install django-storages boto3python
# settings.py
INSTALLED_APPS = [
# ...
'storages',
]
# AWS S3 settings
AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = env('AWS_S3_REGION_NAME', default='us-east-1')
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
# Static files
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/static/'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
# Media files
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/media/'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'5. Database Migrations
Pre-Deployment Migration Check
bash
# Check for unapplied migrations
python manage.py showmigrations
# Check for migration conflicts
python manage.py makemigrations --check --dry-run
# Show SQL for migrations
python manage.py sqlmigrate myapp 0001Safe Migration Deployment
bash
# Step 1: Backup database
pg_dump mydb > backup_$(date +%Y%m%d_%H%M%S).sql
# Step 2: Run migrations
python manage.py migrate --noinput
# Step 3: Verify migrations
python manage.py showmigrationsZero Downtime Migration Strategy
python
# Step 1: Add nullable field (deploy code)
class Migration(migrations.Migration):
operations = [
migrations.AddField(
model_name='product',
name='new_field',
field=models.CharField(max_length=100, null=True),
),
]
# Step 2: Populate data (run migration)
# Step 3: Make field non-nullable (deploy code)
class Migration(migrations.Migration):
operations = [
migrations.AlterField(
model_name='product',
name='new_field',
field=models.CharField(max_length=100),
),
]Migration Rollback Plan
bash
# Rollback to specific migration
python manage.py migrate myapp 0005
# Rollback all migrations for an app
python manage.py migrate myapp zero
# Fake migrations (mark as applied without running)
python manage.py migrate myapp 0005 --fake6. Log Configuration
Basic Logging Setup
python
# settings.py
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_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'file': {
'level': 'WARNING',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/myapp.log',
'maxBytes': 1024 * 1024 * 10, # 10 MB
'backupCount': 5,
'formatter': 'verbose',
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],
},
},
'loggers': {
'django': {
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': False,
},
'django.request': {
'handlers': ['mail_admins', 'file'],
'level': 'ERROR',
'propagate': False,
},
'myapp': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
'propagate': False,
},
},
}Application Logging
python
# myapp/views.py
import logging
logger = logging.getLogger(__name__)
def my_view(request):
logger.debug('Debug message')
logger.info('Info message')
logger.warning('Warning message')
logger.error('Error message')
logger.critical('Critical message')
try:
# Some operation
result = risky_operation()
except Exception as e:
logger.exception('Operation failed')
raise
return render(request, 'template.html')Structured Logging (JSON)
bash
pip install python-json-loggerpython
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'json': {
'()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
'format': '%(asctime)s %(name)s %(levelname)s %(message)s',
},
},
'handlers': {
'json_file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/django/app.json',
'maxBytes': 1024 * 1024 * 10,
'backupCount': 5,
'formatter': 'json',
},
},
'loggers': {
'myapp': {
'handlers': ['json_file'],
'level': 'INFO',
},
},
}7. Error Reporting (Sentry)
Install Sentry SDK
bash
pip install sentry-sdkBasic Sentry Configuration
python
# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=env('SENTRY_DSN'),
integrations=[DjangoIntegration()],
# Performance monitoring
traces_sample_rate=1.0,
# Error sampling
sample_rate=1.0,
# Environment
environment=env('ENVIRONMENT', default='production'),
# Release tracking
release=env('RELEASE_VERSION', default='1.0.0'),
# Send PII (Personally Identifiable Information)
send_default_pii=False,
)Advanced Sentry Configuration
python
# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.celery import CeleryIntegration
def before_send(event, hint):
"""
Filter events before sending to Sentry
"""
# Ignore specific errors
if 'exc_info' in hint:
exc_type, exc_value, tb = hint['exc_info']
if isinstance(exc_value, KeyboardInterrupt):
return None
return event
sentry_sdk.init(
dsn=env('SENTRY_DSN'),
integrations=[
DjangoIntegration(),
RedisIntegration(),
CeleryIntegration(),
],
# Sampling
traces_sample_rate=0.1, # 10% of transactions
profiles_sample_rate=0.1, # 10% profiling
# Environment
environment=env('ENVIRONMENT'),
release=env('RELEASE_VERSION'),
# Filtering
before_send=before_send,
# Additional options
max_breadcrumbs=50,
attach_stacktrace=True,
send_default_pii=False,
)Custom Error Tracking
python
# myapp/views.py
import sentry_sdk
def my_view(request):
try:
# Operation
result = process_data()
except Exception as e:
# Capture exception with context
sentry_sdk.capture_exception(e)
# Add extra context
sentry_sdk.set_context('operation', {
'user_id': request.user.id,
'data': 'some_data',
})
# Add tags
sentry_sdk.set_tag('operation_type', 'data_processing')
# Add breadcrumb
sentry_sdk.add_breadcrumb(
category='operation',
message='Processing started',
level='info',
)
raiseDeployment Checklist
Pre-Deployment Checklist
bash
# ✅ 1. Environment variables configured
cat .env
# ✅ 2. Dependencies installed
pip install -r requirements.txt
# ✅ 3. Database migrations ready
python manage.py makemigrations --check
python manage.py showmigrations
# ✅ 4. Static files collected
python manage.py collectstatic --noinput
# ✅ 5. Tests passing
python manage.py test
# ✅ 6. Security check
python manage.py check --deploy
# ✅ 7. Database backup
pg_dump mydb > backup.sql
# ✅ 8. Logging configured
tail -f /var/log/django/app.log
# ✅ 9. Sentry configured
# Check Sentry dashboard
# ✅ 10. SSL certificate valid
openssl s_client -connect yourdomain.com:443Deployment Script
bash
#!/bin/bash
# deploy.sh
set -e # Exit on error
echo "🚀 Starting deployment..."
# 1. Pull latest code
echo "📥 Pulling latest code..."
git pull origin main
# 2. Install dependencies
echo "📦 Installing dependencies..."
pip install -r requirements.txt
# 3. Collect static files
echo "📁 Collecting static files..."
python manage.py collectstatic --noinput
# 4. Run migrations
echo "🗄️ Running migrations..."
python manage.py migrate --noinput
# 5. Restart application
echo "🔄 Restarting application..."
sudo systemctl restart gunicorn
sudo systemctl restart nginx
# 6. Health check
echo "🏥 Running health check..."
curl -f http://localhost/health/ || exit 1
echo "✅ Deployment completed successfully!"সারসংক্ষেপ
Django application কে production এ deploy করার জন্য proper preparation করুন:
Key Points:
- Settings Management: django-environ দিয়ে environment variables manage করুন
- Environment Variables: .env file ব্যবহার করুন, sensitive data protect করুন
- Production Settings: Security headers, HTTPS, secure cookies configure করুন
- Static Files: collectstatic run করুন, WhiteNoise বা S3 ব্যবহার করুন
- Database Migrations: Safe migration strategy follow করুন, backup নিন
- Logging: Proper logging configure করুন, structured logging ব্যবহার করুন
- Error Reporting: Sentry integrate করুন, real-time error tracking করুন
Deployment preparation properly করলে production এ smooth এবং secure deployment হয়! 🚀