🔧

DEBUG en Django

Guía Completa para Entornos de Desarrollo, Pruebas y Producción

Universidad Tecnológica de Hermosillo

📌 ¿Qué Aprenderás en Esta Guía?

  • Qué es DEBUG y dónde encontrarlo
  • Diferencias entre DEBUG = True y DEBUG = False
  • Riesgos de seguridad con DEBUG activado
  • Configuración correcta para cada entorno
  • Mejores prácticas y recomendaciones profesionales

🔍 ¿Qué es DEBUG en Django?

💡 Definición Simple

DEBUG es una configuración de Django que controla cuánta información técnica muestra tu aplicación cuando algo sale mal.

Es como un "modo desarrollador" que te ayuda a encontrar errores, pero que NUNCA debe estar activo en producción porque expone información sensible.

📂 ¿Dónde se Encuentra DEBUG?

📍 Ubicación del Archivo

El parámetro DEBUG se encuentra en el archivo settings.py de tu proyecto Django:

Estructura del Proyecto Django:

mi_proyecto/
│
├── mi_proyecto/
│   ├── __init__.py
│   ├── asgi.py
│   ├── wsgi.py
│   ├── urls.py
│   └── settings.pyAQUÍ está DEBUG
│
├── mi_app/
│   ├── views.py
│   ├── models.py
│   └── urls.py
│
└── manage.py

Ruta Completa del Archivo:

mi_proyecto/mi_proyecto/settings.py

📝 Cómo se ve en el código

# ========================================
# ARCHIVO: mi_proyecto/settings.py
# ========================================

"""
Configuración de Django para el proyecto
"""

from pathlib import Path

# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-tu-clave-secreta-aqui'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = TrueESTA ES LA LÍNEA QUE BUSCAS

ALLOWED_HOSTS = []

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    # ... más apps
]

# ... resto de configuraciones

🔄 DEBUG = True vs DEBUG = False

🔴 DEBUG = True

Modo: Desarrollo

Descripción: Muestra información detallada de errores

✅ Ventajas:

  • Páginas de error muy detalladas
  • Muestra el código donde ocurrió el error
  • Traceback completo del error
  • Variables locales y globales
  • Consultas SQL realizadas
  • Recarga automática del servidor

❌ Desventajas:

  • RIESGO DE SEGURIDAD CRÍTICO
  • Expone estructura del proyecto
  • Muestra rutas de archivos
  • Revela configuraciones
  • Consume más memoria
  • Más lento

🟢 DEBUG = False

Modo: Producción

Descripción: Muestra páginas de error genéricas

✅ Ventajas:

  • SEGURO para producción
  • No expone información sensible
  • Páginas de error personalizadas
  • Mejor rendimiento
  • Menos consumo de memoria
  • Cumple estándares de seguridad

❌ Desventajas:

  • No muestra detalles de errores
  • Dificulta el debugging
  • Requiere logs para diagnóstico
  • Necesita configurar ALLOWED_HOSTS

⚠️ Comparación Visual: Páginas de Error

🔴 Con DEBUG = True (Desarrollo)

Ejemplo de Pantalla de Error en Modo DEBUG

NameError at /libros/lista/ name 'Libroo' is not defined Python /Users/estudiante/mi_proyecto/libros/views.py in lista_libros Request Method: GET Request URL: http://127.0.0.1:8000/libros/lista/ Django Version: 4.2 Exception Type: NameError Exception Value: name 'Libroo' is not defined ▼ Traceback (most recent call last): File "/Users/estudiante/mi_proyecto/libros/views.py", line 15, in lista_libros libros = Libroo.objects.all() ← ERROR AQUÍ ^^^^^^ NameError: name 'Libroo' is not defined ▼ Local vars: request = <WSGIRequest: GET '/libros/lista/'> self = None ▼ Settings: DEBUG = True SECRET_KEY = 'django-insecure-s3cr3t-k3y-h3r3' DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', ...}} 🚨 TODA ESTA INFORMACIÓN ES VISIBLE PARA CUALQUIERA 🚨

⚠️ ¿Qué información sensible se expone?

  • ✗ Ruta completa de tus archivos en el servidor
  • ✗ Versión de Django que usas (ayuda a hackers a buscar vulnerabilidades)
  • ✗ Estructura de tu código fuente
  • ✗ Variables de configuración
  • ✗ Consultas SQL exactas
  • ✗ Nombres de bases de datos
  • ✗ Secret Key (en algunos casos)

🟢 Con DEBUG = False (Producción)

Ejemplo de Pantalla de Error en Modo PRODUCCIÓN

🚫

Error 500

Algo salió mal

Lo sentimos, estamos experimentando dificultades técnicas. Por favor, inténtalo más tarde.

Volver al Inicio

✅ Ventajas de Seguridad

  • ✓ No muestra información del sistema
  • ✓ No revela estructura del código
  • ✓ Experiencia profesional para el usuario
  • ✓ Los errores se registran en logs internos
  • ✓ Cumple con estándares de seguridad

🌍 Configuración según el Entorno

Entorno DEBUG ALLOWED_HOSTS Propósito Ubicación
🖥️ Desarrollo (Local) DEBUG = True [] (vacío) Programar y detectar errores fácilmente Tu computadora (localhost:8000)
🧪 Pruebas (Testing) DEBUG = False ['testing.miapp.com'] Probar en condiciones similares a producción Servidor de pruebas interno
🌐 Producción (Live) DEBUG = False ['www.miapp.com', 'miapp.com'] Aplicación en vivo con usuarios reales Servidor en Internet (Heroku, AWS, etc.)

📋 Ejemplos de Configuración por Entorno

1️⃣ DESARROLLO (Tu Computadora)

# ========================================
# settings.py - CONFIGURACIÓN DE DESARROLLO
# ========================================

# Permite ver errores detallados mientras programas
DEBUG = True

# No es necesario especificar hosts en desarrollo local
ALLOWED_HOSTS = []

# Puedes usar SQLite para desarrollo (más simple)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Servidor de desarrollo integrado
# Ejecutar: python manage.py runserver
# Acceder: http://127.0.0.1:8000/

2️⃣ PRUEBAS (Servidor de Testing)

# ========================================
# settings.py - CONFIGURACIÓN DE PRUEBAS
# ========================================

# Simular entorno de producción para detectar problemas
DEBUG = False

# Especificar dominio de pruebas
ALLOWED_HOSTS = ['testing.biblioteca-uth.com', '192.168.1.100']

# Base de datos de pruebas (copia de producción)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'biblioteca_testing',
        'USER': 'test_user',
        'PASSWORD': 'test_password',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

# Configurar archivos estáticos
STATIC_ROOT = '/var/www/testing/static/'

# Logging para capturar errores
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'ERROR',
            'class': 'logging.FileHandler',
            'filename': '/var/log/django/testing.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'ERROR',
            'propagate': True,
        },
    },
}

3️⃣ PRODUCCIÓN (Servidor en Internet)

# ========================================
# settings.py - CONFIGURACIÓN DE PRODUCCIÓN
# ========================================

# ¡NUNCA usar DEBUG = True en producción!
DEBUG = False

# Dominios permitidos (tu sitio web)
ALLOWED_HOSTS = [
    'www.biblioteca-uth.com',
    'biblioteca-uth.com',
    '52.201.123.45'  # IP del servidor si es necesario
]

# Base de datos de producción
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'biblioteca_production',
        'USER': 'prod_user',
        'PASSWORD': os.environ.get('DB_PASSWORD'),  # Desde variable de entorno
        'HOST': 'db.biblioteca-uth.com',
        'PORT': '3306',
    }
}

# Secret Key desde variable de entorno (seguridad)
SECRET_KEY = os.environ.get('SECRET_KEY')

# Configuración de archivos estáticos
STATIC_ROOT = '/var/www/biblioteca/static/'
STATIC_URL = '/static/'

# Configuración de seguridad adicional
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True

# Logging profesional
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'file': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': '/var/log/django/production.log',
            'maxBytes': 1024*1024*15,  # 15MB
            'backupCount': 10,
            'formatter': 'verbose',
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        }
    },
    'loggers': {
        'django': {
            'handlers': ['file', 'mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    },
}

🚨 Riesgos de Seguridad con DEBUG = True

⚠️ PELIGROS REALES

Si dejas DEBUG = True en producción, un atacante puede:

1. Ver la Estructura de tu Proyecto

File "/home/usuario/biblioteca_project/libros/views.py"
     line 15, in lista_libros

→ Ahora el atacante sabe dónde están tus archivos

2. Conocer tus Consultas SQL

SELECT * FROM libros_libro 
WHERE usuario_id = 1 
AND password = 'admin123'

→ Expone estructura de la base de datos

3. Ver Variables Sensibles

Local vars:
  api_key = 'sk_live_123456789'
  password = 'MiClaveSecreta'
  
→ Expone credenciales y claves API

4. Identificar Versiones de Software

Django Version: 3.2.5
Python Version: 3.9.1

→ Puede buscar vulnerabilidades conocidas

💀 Caso Real: Consecuencias

Escenario: Una empresa dejó DEBUG = True en producción durante 2 semanas.

  • ❌ Un atacante provocó errores a propósito para ver las páginas de debug
  • ❌ Obtuvo rutas completas del servidor
  • ❌ Vio la estructura de la base de datos en las consultas SQL
  • ❌ Identificó la versión de Django con vulnerabilidades conocidas
  • ❌ Explotó una vulnerabilidad y accedió a datos de clientes
  • Resultado: Multa de $50,000 USD por violación de datos personales

✅ Mejores Prácticas

🎯 Recomendaciones Profesionales

1️⃣ Usar Variables de Entorno

No escribir directamente en settings.py, usar archivos .env:

# Instalar: pip install python-decouple

# ========================================
# Archivo: .env (NO subir a Git)
# ========================================
DEBUG=False
SECRET_KEY=tu-clave-super-secreta-aqui
ALLOWED_HOSTS=www.miapp.com,miapp.com
DB_PASSWORD=contraseña-base-datos


# ========================================
# Archivo: settings.py
# ========================================
from decouple import config

DEBUG = config('DEBUG', default=False, cast=bool)
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS').split(',')
DATABASES = {
    'default': {
        'PASSWORD': config('DB_PASSWORD'),
        # ...
    }
}

2️⃣ Diferentes Archivos de Configuración

mi_proyecto/settings/
├── __init__.py
├── base.py           ← Configuración común
├── development.py    ← DEBUG = True
├── testing.py        ← DEBUG = False
└── production.py     ← DEBUG = False + seguridad

# Ejecutar según entorno:
python manage.py runserver --settings=mi_proyecto.settings.development
python manage.py runserver --settings=mi_proyecto.settings.production

3️⃣ Configurar ALLOWED_HOSTS Correctamente

# ❌ MAL - Permite todos los hosts (inseguro)
ALLOWED_HOSTS = ['*']

# ✅ BIEN - Solo dominios específicos
ALLOWED_HOSTS = [
    'www.biblioteca-uth.com',
    'biblioteca-uth.com',
]

# ✅ BIEN - Para desarrollo local
ALLOWED_HOSTS = ['localhost', '127.0.0.1']

4️⃣ Configurar Logging para Producción

Cuando DEBUG = False, necesitas logs para ver errores:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'ERROR',
            'class': 'logging.FileHandler',
            'filename': '/var/log/django/errors.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'ERROR',
            'propagate': True,
        },
    },
}

# Los errores se guardarán en el archivo en lugar de mostrarse

5️⃣ Revisar Antes de Desplegar

Django incluye un comando para verificar configuración de producción:

python manage.py check --deploy

Ejemplo de salida:
System check identified some issues:

WARNINGS:
?: (security.W004) You have not set a value for SECURE_HSTS_SECONDS.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True.
?: (security.W012) SESSION_COOKIE_SECURE is not set to True.

Corregir cada advertencia antes de producción

📊 Checklist de Despliegue

Verificación Comando/Archivo
DEBUG = False settings.py
SECRET_KEY desde variable de entorno os.environ.get('SECRET_KEY')
ALLOWED_HOSTS configurado ['www.miapp.com']
Archivos estáticos recolectados python manage.py collectstatic
Migraciones aplicadas python manage.py migrate
Verificación de seguridad python manage.py check --deploy
Logging configurado settings.py - LOGGING
HTTPS configurado (SSL) SECURE_SSL_REDIRECT = True
Cookies seguras SESSION_COOKIE_SECURE = True
Backup de base de datos Script automatizado

🎓 Resumen para Estudiantes UTH

📝 Lo que DEBES Recordar

DEBUG = True Solo para DESARROLLO en tu computadora
DEBUG = False SIEMPRE en PRODUCCIÓN (Internet)
Ubicación mi_proyecto/settings.py
Riesgo Expone información sensible del sistema
Verificación python manage.py check --deploy

⚡ Regla de Oro

"Si tu aplicación está en Internet
donde otros pueden acceder,
DEBUG DEBE ser False"

📚 Recursos Adicionales

🔗 Enlaces Útiles