DEV Community

Cover image for Django Security: 10 Essential Steps to Secure Your Project Before Production
sizan mahmud0
sizan mahmud0

Posted on

Django Security: 10 Essential Steps to Secure Your Project Before Production

The Ultimate Production Security Checklist for Django Developers in 2026

You've built an amazing Django application. Your features work perfectly, tests are passing, and you're ready to launch. But waitβ€”is your application really secure?

Every day, thousands of Django applications get hacked because developers skip critical security steps. A single vulnerability can lead to data breaches, financial losses, and destroyed reputations.

In this comprehensive guide, you'll learn 10 essential security practices that every Django developer must implement before going to production. Plus, I'll show you how to handle high traffic like a pro!

By the end of this article, you'll know exactly how to:

  • βœ… Secure your Django settings properly
  • βœ… Prevent common security vulnerabilities
  • βœ… Handle thousands of concurrent users
  • βœ… Monitor and respond to security threats
  • βœ… Pass security audits with confidence

Before diving in, join our community to get more updates about Django JOIN. Let's dive in and make your Django app bulletproof! πŸ›‘οΈ


🚨 Why Django Security Matters

Before we start, consider these sobering statistics:

  • 43% of cyberattacks target small businesses and startups
  • 60% of companies go out of business within 6 months of a data breach
  • Average cost of a data breach: $4.45 million

Django provides excellent security features out of the box, but YOU must configure them correctly. One misconfiguration can expose your entire application.


Security Tip #1: Lock Down Your Django Settings

The Problem

Default Django settings are designed for development, not production. Running with DEBUG=True in production is like leaving your front door wide open.

The Solution

# settings/production.py
import os
from pathlib import Path

# CRITICAL: Never run with DEBUG=True in production
DEBUG = False

# Restrict which hosts can access your application
ALLOWED_HOSTS = [
    'yourdomain.com',
    'www.yourdomain.com',
    'api.yourdomain.com',
]

# Generate a strong SECRET_KEY and keep it secret!
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
if not SECRET_KEY:
    raise ValueError("DJANGO_SECRET_KEY environment variable must be set!")

# Security Headers
SECURE_SSL_REDIRECT = True  # Force HTTPS
SESSION_COOKIE_SECURE = True  # Only send cookies over HTTPS
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking

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

# Proxy settings (if behind nginx/load balancer)
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = True
Enter fullscreen mode Exit fullscreen mode

Generate a Strong SECRET_KEY

# generate_secret_key.py
from django.core.management.utils import get_random_secret_key

print(f"Your new SECRET_KEY: {get_random_secret_key()}")
Enter fullscreen mode Exit fullscreen mode

Pro Tip: Never commit your SECRET_KEY to version control! Use environment variables or secret management tools like AWS Secrets Manager or HashiCorp Vault.


Security Tip #2: Implement Proper Authentication & Authorization

The Problem

Weak authentication allows attackers to gain unauthorized access. Poor authorization lets users access data they shouldn't see.

The Solution

# settings.py
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 12,  # Require strong passwords
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Session Security
SESSION_COOKIE_AGE = 3600  # 1 hour
SESSION_COOKIE_HTTPONLY = True  # Prevent JavaScript access
SESSION_COOKIE_SAMESITE = 'Strict'  # Prevent CSRF
SESSION_SAVE_EVERY_REQUEST = True  # Extend session on activity

# Password hashing (use Argon2 for best security)
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
]
Enter fullscreen mode Exit fullscreen mode

Install Argon2

pip install django[argon2]
Enter fullscreen mode Exit fullscreen mode

Implement Two-Factor Authentication

# Install django-otp
pip install django-otp qrcode

# settings.py
INSTALLED_APPS = [
    # ...
    'django_otp',
    'django_otp.plugins.otp_totp',
]

MIDDLEWARE = [
    # ...
    'django_otp.middleware.OTPMiddleware',
]

# views.py
from django_otp.decorators import otp_required

@otp_required
def sensitive_view(request):
    # This view requires 2FA
    return render(request, 'sensitive.html')
Enter fullscreen mode Exit fullscreen mode

Advanced: Rate Limiting Login Attempts

# middleware.py
from django.core.cache import cache
from django.http import HttpResponseForbidden
import time

class LoginRateLimitMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path == '/accounts/login/' and request.method == 'POST':
            ip = self.get_client_ip(request)
            cache_key = f'login_attempts_{ip}'

            attempts = cache.get(cache_key, 0)

            if attempts >= 5:  # Max 5 attempts
                return HttpResponseForbidden(
                    'Too many login attempts. Try again in 15 minutes.'
                )

            cache.set(cache_key, attempts + 1, 900)  # 15 minutes

        return self.get_response(request)

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
Enter fullscreen mode Exit fullscreen mode

Security Tip #3: Prevent SQL Injection Attacks

The Problem

SQL injection is one of the most common and dangerous vulnerabilities. It allows attackers to execute arbitrary database queries.

The Solution

❌ NEVER DO THIS:

# DANGEROUS! Vulnerable to SQL injection
def get_user_data(request):
    user_id = request.GET.get('id')
    query = f"SELECT * FROM users WHERE id = {user_id}"
    cursor.execute(query)  # UNSAFE!
Enter fullscreen mode Exit fullscreen mode

βœ… ALWAYS DO THIS:

# SAFE: Use Django ORM
def get_user_data(request):
    user_id = request.GET.get('id')
    user = User.objects.filter(id=user_id).first()

# SAFE: Use parameterized queries if you need raw SQL
def get_user_data_raw(request):
    user_id = request.GET.get('id')
    cursor.execute(
        "SELECT * FROM users WHERE id = %s",
        [user_id]  # Parameters are properly escaped
    )
Enter fullscreen mode Exit fullscreen mode

Additional Protection: Input Validation

from django.core.validators import validate_email
from django.core.exceptions import ValidationError

def create_user(request):
    email = request.POST.get('email')

    try:
        validate_email(email)
    except ValidationError:
        return JsonResponse({'error': 'Invalid email'}, status=400)

    # Safe to proceed
    User.objects.create(email=email)
Enter fullscreen mode Exit fullscreen mode

Security Tip #4: Protect Against XSS (Cross-Site Scripting)

The Problem

XSS attacks inject malicious JavaScript into your pages, stealing cookies, sessions, and sensitive data.

The Solution

# Django automatically escapes variables in templates
# This is SAFE:
<p>{{ user.name }}</p>  <!-- Automatically escaped -->

# If you MUST render HTML, sanitize it first
# Install bleach
pip install bleach

# utils.py
import bleach

ALLOWED_TAGS = ['p', 'br', 'strong', 'em', 'a']
ALLOWED_ATTRIBUTES = {'a': ['href', 'title']}

def sanitize_html(dirty_html):
    return bleach.clean(
        dirty_html,
        tags=ALLOWED_TAGS,
        attributes=ALLOWED_ATTRIBUTES,
        strip=True
    )

# views.py
from django.utils.safestring import mark_safe

def display_content(request):
    user_content = request.POST.get('content')
    clean_content = sanitize_html(user_content)
    return render(request, 'page.html', {
        'content': mark_safe(clean_content)
    })
Enter fullscreen mode Exit fullscreen mode

Content Security Policy (CSP)

# Install django-csp
pip install django-csp

# settings.py
MIDDLEWARE = [
    # ...
    'csp.middleware.CSPMiddleware',
]

CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'", 'cdn.jsdelivr.net')
CSP_STYLE_SRC = ("'self'", 'fonts.googleapis.com')
CSP_FONT_SRC = ("'self'", 'fonts.gstatic.com')
CSP_IMG_SRC = ("'self'", 'data:', 'https:')
CSP_CONNECT_SRC = ("'self'",)
Enter fullscreen mode Exit fullscreen mode

Security Tip #5: Secure File Uploads

The Problem

Unrestricted file uploads can lead to remote code execution, malware distribution, and server compromise.

The Solution

# settings.py
# Limit file upload size
DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880  # 5MB

# Restrict file types
ALLOWED_UPLOAD_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.pdf', '.docx']

# Store uploads outside web root
MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = '/media/'

# models.py
from django.core.validators import FileExtensionValidator
from django.core.exceptions import ValidationError

def validate_file_size(file):
    max_size_mb = 5
    if file.size > max_size_mb * 1024 * 1024:
        raise ValidationError(f'File size cannot exceed {max_size_mb}MB')

class Document(models.Model):
    file = models.FileField(
        upload_to='documents/%Y/%m/%d/',
        validators=[
            FileExtensionValidator(
                allowed_extensions=['pdf', 'docx', 'jpg', 'png']
            ),
            validate_file_size,
        ]
    )

# views.py
from PIL import Image
import magic

def upload_image(request):
    if request.method == 'POST':
        uploaded_file = request.FILES['image']

        # Verify file type using python-magic
        file_type = magic.from_buffer(uploaded_file.read(1024), mime=True)
        uploaded_file.seek(0)

        if file_type not in ['image/jpeg', 'image/png']:
            return JsonResponse({'error': 'Invalid file type'}, status=400)

        # Verify image integrity
        try:
            img = Image.open(uploaded_file)
            img.verify()
        except Exception:
            return JsonResponse({'error': 'Corrupted image'}, status=400)

        # Safe to save
        document = Document.objects.create(file=uploaded_file)
        return JsonResponse({'success': True})
Enter fullscreen mode Exit fullscreen mode

Scan Uploads for Malware

# Install ClamAV
pip install clamd

# utils.py
import clamd

def scan_file_for_malware(file_path):
    cd = clamd.ClamdUnixSocket()
    scan_result = cd.scan(file_path)

    if scan_result[file_path][0] == 'FOUND':
        return False, scan_result[file_path][1]  # Malware found
    return True, None  # Clean
Enter fullscreen mode Exit fullscreen mode

Security Tip #6: Protect Your APIs

The Problem

APIs are prime targets for attacks: brute force, data scraping, DDoS, and more.

The Solution

# Install Django REST Framework and throttling
pip install djangorestframework

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/hour',
        'user': '1000/hour',
    },
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
}

# Use JWT for stateless authentication
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
}

# views.py - Custom throttling
from rest_framework.throttling import UserRateThrottle

class BurstRateThrottle(UserRateThrottle):
    scope = 'burst'
    rate = '10/min'

class SustainedRateThrottle(UserRateThrottle):
    scope = 'sustained'
    rate = '1000/day'

class MyAPIView(APIView):
    throttle_classes = [BurstRateThrottle, SustainedRateThrottle]

    def get(self, request):
        return Response({'data': 'protected'})
Enter fullscreen mode Exit fullscreen mode

API Key Management

# models.py
import secrets

class APIKey(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    key = models.CharField(max_length=64, unique=True)
    name = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    last_used = models.DateTimeField(null=True)
    is_active = models.BooleanField(default=True)

    def save(self, *args, **kwargs):
        if not self.key:
            self.key = secrets.token_urlsafe(32)
        super().save(*args, **kwargs)

# authentication.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class APIKeyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        api_key = request.META.get('HTTP_X_API_KEY')

        if not api_key:
            return None

        try:
            key_obj = APIKey.objects.get(key=api_key, is_active=True)
            key_obj.last_used = timezone.now()
            key_obj.save(update_fields=['last_used'])
            return (key_obj.user, None)
        except APIKey.DoesNotExist:
            raise AuthenticationFailed('Invalid API key')
Enter fullscreen mode Exit fullscreen mode

Security Tip #7: Database Security Best Practices

The Problem

Database breaches expose sensitive user data, leading to regulatory fines and loss of trust.

The Solution

# settings.py - Use environment variables
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST'),
        'PORT': os.environ.get('DB_PORT', '5432'),
        'OPTIONS': {
            'sslmode': 'require',  # Require SSL connection
            'connect_timeout': 10,
        },
        'CONN_MAX_AGE': 600,
    }
}

# Encrypt sensitive data
pip install django-fernet-fields

# models.py
from fernet_fields import EncryptedTextField, EncryptedCharField

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    ssn = EncryptedCharField(max_length=11)  # Encrypted at rest
    credit_card = EncryptedCharField(max_length=16)
    address = EncryptedTextField()

# Backup encryption key in settings.py
FERNET_KEYS = [
    os.environ.get('FERNET_KEY'),
]
Enter fullscreen mode Exit fullscreen mode

Database Access Control

-- Create read-only user for reporting
CREATE USER reporting_user WITH PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE mydb TO reporting_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporting_user;

-- Create limited user for application
CREATE USER app_user WITH PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE mydb TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
REVOKE CREATE ON SCHEMA public FROM app_user;
Enter fullscreen mode Exit fullscreen mode

Audit Logging

# Install django-auditlog
pip install django-auditlog

# settings.py
INSTALLED_APPS = [
    # ...
    'auditlog',
]

# models.py
from auditlog.registry import auditlog

class SensitiveData(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    data = models.TextField()

auditlog.register(SensitiveData)

# Now all changes are automatically logged!
Enter fullscreen mode Exit fullscreen mode

Security Tip #8: Implement Security Monitoring

The Problem

You can't fix what you don't know about. Without monitoring, breaches go undetected for months.

The Solution

# Install Sentry for error tracking
pip install sentry-sdk

# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn=os.environ.get('SENTRY_DSN'),
    integrations=[DjangoIntegration()],
    traces_sample_rate=1.0,
    send_default_pii=False,  # Don't send personally identifiable information
    environment=os.environ.get('ENVIRONMENT', 'production'),
)

# Custom security event logging
# middleware.py
import logging

security_logger = logging.getLogger('security')

class SecurityMonitoringMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Log suspicious activity
        if self.is_suspicious(request):
            security_logger.warning(
                f'Suspicious request from {self.get_client_ip(request)}',
                extra={
                    'ip': self.get_client_ip(request),
                    'path': request.path,
                    'user': request.user.username if request.user.is_authenticated else 'anonymous',
                    'user_agent': request.META.get('HTTP_USER_AGENT'),
                }
            )

        response = self.get_response(request)
        return response

    def is_suspicious(self, request):
        # Check for common attack patterns
        suspicious_patterns = [
            '../', '..\\',  # Path traversal
            '<script', 'javascript:',  # XSS attempts
            'union select', 'drop table',  # SQL injection
            '<?php',  # PHP code injection
        ]

        query_string = request.META.get('QUERY_STRING', '').lower()
        path = request.path.lower()

        return any(pattern in query_string or pattern in path 
                  for pattern in suspicious_patterns)

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

# settings.py - Configure logging
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'file': {
            'level': 'WARNING',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': '/var/log/django/security.log',
            'maxBytes': 1024 * 1024 * 15,  # 15MB
            'backupCount': 10,
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'security': {
            'handlers': ['file'],
            'level': 'WARNING',
            'propagate': False,
        },
    },
}
Enter fullscreen mode Exit fullscreen mode

Security Tip #9: Secure Your Dependencies

The Problem

Third-party packages can have vulnerabilities that compromise your entire application.

The Solution

# Install safety to check for known vulnerabilities
pip install safety

# Check your dependencies
safety check

# Scan with Bandit for security issues in your code
pip install bandit
bandit -r . -f json -o security-report.json

# Keep dependencies updated
pip install pip-audit
pip-audit

# Use requirements with pinned versions
pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

Automated Dependency Scanning

# .github/workflows/security-scan.yml
name: Security Scan

on:
  schedule:
    - cron: '0 0 * * 0'  # Run weekly
  push:
    branches: [main]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install safety bandit pip-audit
          pip install -r requirements.txt

      - name: Run Safety check
        run: safety check --json

      - name: Run Bandit scan
        run: bandit -r . -f json -o bandit-report.json

      - name: Run pip-audit
        run: pip-audit

      - name: Upload results
        uses: actions/upload-artifact@v3
        with:
          name: security-reports
          path: bandit-report.json
Enter fullscreen mode Exit fullscreen mode

Security Tip #10: Handle High Traffic Securely

The Problem

Traffic spikes can bring down your application or be exploited for DDoS attacks.

The Solution

1. Implement Caching

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': os.environ.get('REDIS_URL', 'redis://127.0.0.1:6379/1'),
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            'PASSWORD': os.environ.get('REDIS_PASSWORD'),
        },
        'KEY_PREFIX': 'myapp',
        'TIMEOUT': 300,
    }
}

# views.py
from django.views.decorators.cache import cache_page
from django.core.cache import cache

@cache_page(60 * 15)  # Cache for 15 minutes
def homepage(request):
    return render(request, 'home.html')

# Cache expensive queries
def get_popular_posts():
    cache_key = 'popular_posts'
    posts = cache.get(cache_key)

    if posts is None:
        posts = Post.objects.annotate(
            like_count=Count('likes')
        ).order_by('-like_count')[:10]
        cache.set(cache_key, posts, 3600)  # Cache for 1 hour

    return posts
Enter fullscreen mode Exit fullscreen mode

2. Database Connection Pooling

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        # ...
        'CONN_MAX_AGE': 600,  # Keep connections alive for 10 minutes
        'OPTIONS': {
            'pool': True,
            'pool_size': 20,  # Maximum connections in pool
            'max_overflow': 10,  # Additional connections when pool is full
        },
    }
}

# Install pgbouncer for production
# Ubuntu/Debian:
# sudo apt-get install pgbouncer
Enter fullscreen mode Exit fullscreen mode

3. Load Balancing with Nginx

# /etc/nginx/sites-available/myapp
upstream django_app {
    least_conn;  # Use least connections algorithm
    server 127.0.0.1:8001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8002 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8003 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name myapp.com;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;

    # DDoS protection
    client_body_timeout 10s;
    client_header_timeout 10s;
    keepalive_timeout 5s 5s;
    send_timeout 10s;

    location / {
        limit_req zone=general burst=20 nodelay;

        proxy_pass http://django_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api/ {
        limit_req zone=api burst=50 nodelay;

        proxy_pass http://django_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Serve static files directly
    location /static/ {
        alias /var/www/myapp/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Asynchronous Task Processing

# Install Celery
pip install celery redis

# celery.py
from celery import Celery
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# settings.py
CELERY_BROKER_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
CELERY_RESULT_BACKEND = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'

# tasks.py
from celery import shared_task
from django.core.mail import send_mail

@shared_task
def send_email_async(subject, message, recipient):
    send_mail(
        subject,
        message,
        'noreply@myapp.com',
        [recipient],
        fail_silently=False,
    )

# views.py
def register_user(request):
    # ... user registration logic ...

    # Send welcome email asynchronously
    send_email_async.delay(
        'Welcome to MyApp',
        'Thank you for registering!',
        user.email
    )

    return redirect('dashboard')
Enter fullscreen mode Exit fullscreen mode

5. Auto-Scaling Configuration

# docker-compose.yml with auto-scaling
version: '3.9'

services:
  web:
    image: myapp:latest
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
Enter fullscreen mode Exit fullscreen mode

🎯 Production Security Checklist

Before deploying, verify:

Settings

  • [ ] DEBUG = False
  • [ ] SECRET_KEY is secure and not in version control
  • [ ] ALLOWED_HOSTS is properly configured
  • [ ] All security middleware enabled
  • [ ] HTTPS enforced (SECURE_SSL_REDIRECT = True)
  • [ ] Secure cookies configured

Authentication & Authorization

  • [ ] Strong password requirements
  • [ ] Session security configured
  • [ ] Rate limiting on login implemented
  • [ ] 2FA available for sensitive accounts
  • [ ] API authentication properly secured

Data Protection

  • [ ] SQL injection prevention (using ORM)
  • [ ] XSS protection enabled
  • [ ] CSRF protection active
  • [ ] File upload validation
  • [ ] Sensitive data encrypted

Infrastructure

  • [ ] Database credentials secured
  • [ ] SSL/TLS certificates installed
  • [ ] Firewall configured
  • [ ] Regular backups scheduled
  • [ ] Monitoring and logging active

Dependencies

  • [ ] All packages updated
  • [ ] Security vulnerabilities scanned
  • [ ] Unused dependencies removed
  • [ ] Requirements.txt pinned versions

Performance & Scaling

  • [ ] Caching implemented
  • [ ] Database optimized
  • [ ] Static files served efficiently
  • [ ] CDN configured
  • [ ] Load balancing ready

πŸš€ Join Our Django Developer Community!

Want to learn more about Django security and best practices?
Continue your journey with django community

Top comments (0)