← Volver al Índice Principal 📋 Templates Listos 🔧 Solución Permisos 💾 Sistema Local 🌐 Guía ngrok

🌐 Facebook API + Django + MySQL

Guía Completa - Unidad II: Redes Sociales

🎯 INTRODUCCIÓN - ¿Qué Vamos a Lograr?

Objetivo del Sistema

Este sistema permitirá crear una aplicación web completa que se integre con Facebook para ofrecer las siguientes funcionalidades:

  1. 🔐 Autenticación Social: Los usuarios podrán iniciar sesión usando sus cuentas de Facebook (Login con Facebook) sin necesidad de crear credenciales nuevas
  2. 📝 Publicación Automatizada en Páginas:
    • Permitir que los usuarios publiquen contenido directamente en sus Páginas de Facebook desde nuestra aplicación web
    • ⚠️ NOTA IMPORTANTE 2026: Facebook bloqueó publicaciones en perfiles personales vía API desde 2018. Solo se puede publicar en Páginas de Facebook
    • Solución: Cada usuario creará una Página de prueba (proceso guiado en Fase 1)
  3. 📊 Gestión de Datos: Almacenar información de usuarios y publicaciones en una base de datos MySQL para análisis y seguimiento
  4. 👤 Perfil Integrado: Obtener y mostrar información básica del perfil de Facebook (nombre, foto, email) dentro de nuestra aplicación
  5. 📈 Métricas Sociales: Rastrear interacciones (likes, comentarios, compartidos) de las publicaciones realizadas en las Páginas
  6. 📋 Gestión de Páginas: Listar y administrar las Páginas de Facebook que el usuario gestiona

¿Qué Hará el Sistema Completo?

Flujo de Usuario Final (Actualizado 2026):

  1. El usuario accede a nuestra aplicación web
  2. Hace clic en "Iniciar sesión con Facebook"
  3. Facebook solicita permisos y autentica al usuario:
    • Permiso para acceder a perfil público (nombre, foto)
    • Permiso para acceder al correo electrónico
    • Permiso para acceder a la lista de Páginas administradas
    • Permiso para publicar en las Páginas del usuario
  4. El usuario es redirigido a un dashboard personalizado que muestra:
    • Su foto de perfil y nombre de Facebook
    • Lista de Páginas de Facebook que administra
    • Formulario para crear nuevas publicaciones en sus Páginas
    • Historial de publicaciones realizadas con estadísticas
  5. El usuario selecciona en qué Página desea publicar (o el sistema usa la primera por defecto)
  6. El usuario escribe un mensaje y lo publica en su Página de Facebook desde nuestro sistema
  7. La publicación aparece simultáneamente en la Página de Facebook y se guarda en nuestra base de datos
  8. El sistema actualiza las métricas de interacción periódicamente (likes, comentarios, compartidos)

⚠️ Nota Importante 2026:
Las publicaciones se realizan en Páginas de Facebook, NO en perfiles personales. Esto es una política de Facebook vigente desde 2018 y mantenida en 2026. Cada usuario debe administrar al menos una Página de Facebook (el proceso de creación está incluido en la Fase 1).

Tecnologías Utilizadas (Actualizado 2026)

  • Backend: Django 4.2+ o Django 5.0 (Framework Python) - Gestiona lógica de negocio, autenticación y comunicación con APIs
  • Base de Datos: MySQL 8.0+ - Almacena usuarios, tokens de acceso, publicaciones y métricas
  • API Externa: Facebook Graph API v19.0 (2026) - Interfaz para comunicarse con Facebook
    • ✅ Versión más reciente estable en 2026
    • ✅ Soporte completo para Páginas de Facebook
    • ✅ Endpoints actualizados para publicaciones
  • Autenticación: OAuth 2.0 - Protocolo estándar para login social seguro
  • Frontend: HTML5/CSS3/JavaScript ES6+ - Interfaz de usuario moderna y responsiva
  • Despliegue (Opcional): PythonAnywhere - Plataforma cloud gratuita para hosting de aplicaciones Python
  • Control de Versiones: Git - Recomendado para gestionar cambios en el código

💡 Versión de Graph API:
Este tutorial usa Graph API v19.0 (versión 2026). Si Facebook lanza versiones más nuevas, los endpoints principales se mantienen compatibles. Puedes verificar la versión actual en: Graph API Changelog

📚 SABER - Fundamentos Teóricos

¿Qué es Facebook Graph API?

Facebook Graph API es la interfaz principal para interactuar programáticamente con los datos de Facebook. Funciona como un "puente" que permite a nuestra aplicación comunicarse con Facebook de forma estructurada y segura.

Analogía: Imagina que Facebook es un banco y tu aplicación quiere acceder a la cuenta del usuario. La Graph API es el cajero automático que proporciona una interfaz segura para realizar operaciones autorizadas (consultar saldo = obtener perfil, hacer depósito = publicar post).

💡 Conceptos Clave:
  • OAuth 2.0: Sistema de autenticación seguro que permite login social. Es como darle a nuestra aplicación una "tarjeta de acceso temporal" en lugar de la contraseña completa del usuario
  • Access Tokens: Credenciales temporales (como un pase VIP) que permiten acceder a datos del usuario. Tienen fecha de expiración y permisos limitados
  • Graph API: Estructura basada en:
    • Nodos: Objetos individuales (usuarios, páginas, fotos, posts)
    • Edges: Conexiones entre nodos (posts de un usuario, comentarios de un post)
    • Fields: Propiedades de cada nodo (nombre, email, fecha de creación)
  • Permissions/Scopes (Actualizado 2026): Permisos granulares que el usuario otorga a la aplicación:
    • public_profile - Acceso a nombre y foto pública (básico, siempre concedido)
    • email - Acceso al correo electrónico del usuario
    • pages_show_list - Listar Páginas de Facebook administradas por el usuario
    • pages_manage_posts - PUBLICAR contenido en Páginas (esencial para este proyecto)
    • pages_read_engagement - Leer métricas de interacción (likes, comentarios, compartidos)
    • pages_read_user_content - Leer contenido de las Páginas
    • publish_to_groups - Requiere App Review (no necesario para este proyecto)
    • user_posts - Solo lectura de posts del perfil personal (no permite publicar)

    ⚠️ Importante 2026: Los permisos de Páginas (pages_*) están disponibles automáticamente en modo Development. NO necesitas App Review para usarlos en proyectos educativos.

Arquitectura del Sistema

┌─────────────┐         ┌──────────────┐         ┌─────────────┐
│   Usuario   │────────>│  Aplicación  │────────>│  Facebook   │
│  (Browser)  │<────────│    Django    │<────────│  Graph API  │
└─────────────┘         └──────────────┘         └─────────────┘
                              │    │
                              │    │
                              v    v
                        ┌──────────────┐
                        │    MySQL     │
                        │  (Base Datos)│
                        └──────────────┘

Flujo de Datos:
1. Usuario → Django: Solicitud de login con Facebook
2. Django → Facebook: Redirección para autorización
3. Facebook → Usuario: Solicita permisos
4. Usuario → Facebook: Autoriza aplicación
5. Facebook → Django: Envía código de autorización
6. Django → Facebook: Intercambia código por access_token
7. Facebook → Django: Devuelve token y datos del usuario
8. Django → MySQL: Guarda usuario y token
9. Django → Usuario: Muestra dashboard personalizado
            

🛠️ SABER HACER - Desarrollo Paso a Paso

⚠️ IMPORTANTE

¿Recibes Error de Permisos al probar /facebook/login/?

¡NO necesitas verificación de negocio ni App Review!

Facebook permite usar la API en Modo Development sin restricciones para proyectos universitarios.

🔧 Ver Solución Completa (Modo Development)

✅ Sin verificación de negocio | ✅ 100% gratis | ✅ Perfecto para UTH

⚙️ Antes de Comenzar - Requisitos Previos (VERIFICAR UNO POR UNO)

Asegúrate de tener instalado:

1. Python 3.8 o superior

¿Cómo verificar? Abre una terminal/cmd y ejecuta:

python --version

Debe mostrar: Python 3.8.x, Python 3.9.x, Python 3.10.x o superior

❌ Si no está instalado: Descarga de python.org/downloads

💡 Al instalar: MARCA la casilla "Add Python to PATH" durante la instalación

2. MySQL Server 8.0 o superior

¿Cómo verificar? Abre terminal/cmd y ejecuta:

mysql --version

Debe mostrar: mysql Ver 8.0.x o superior

❌ Si no está instalado:

  • Windows: Descarga MySQL Installer o instala XAMPP (incluye MySQL)
  • Mac: brew install mysql (requiere Homebrew)
  • Linux: sudo apt install mysql-server (Ubuntu/Debian)

💡 Anota tu contraseña de root MySQL: La necesitarás más adelante

3. Cuenta de Facebook activa

  • ✅ Cuenta personal con correo verificado
  • ✅ Número de teléfono agregado (Facebook lo requiere para desarrolladores)
  • ✅ Autenticación de dos factores activada (recomendado)

4. Editor de Código

Recomendado para principiantes: Visual Studio Code (gratis)

Alternativas: PyCharm Community Edition, Sublime Text, Notepad++

5. Navegador Web Moderno

Chrome, Firefox o Edge (actualizados a última versión)

6. Conexión a Internet Estable

Necesaria para comunicarse con la API de Facebook


📅 Tiempo estimado: 1-2 horas para implementación completa (primera vez)

🎯 Nivel de dificultad: Intermedio (requiere seguir instrucciones al pie de la letra)

🧭 Estructura del Tutorial

Este tutorial está dividido en 9 FASES que debes completar en orden:

  1. FASE 1: Configurar cuenta Facebook Developer (20 min)
  2. FASE 2: Instalar Django y dependencias (15 min)
  3. FASE 3: Configurar base de datos MySQL (20 min)
  4. FASE 4: Crear modelos de datos (15 min)
  5. FASE 5: Programar lógica de autenticación (30 min)
  6. FASE 6: Configurar rutas URL (10 min)
  7. FASE 7: Crear templates HTML (20 min) ← NUEVO
  8. FASE 8: Migrar base de datos y probar (30 min)
  9. FASE 9: Desplegar en PythonAnywhere (60 min)

💡 Consejo: Completa cada fase completamente antes de continuar a la siguiente. Verifica que todo funcione en cada paso. El tiempo es solo un estimado, puedes terminar antes.

📸 VISTA PREVIA DEL SISTEMA

Así se verá tu sistema funcionando:

🖥️ Apartado 1: Dashboard Principal

📊

Dashboard del Sistema (Muestra: nombre de usuario, foto de perfil, lista de páginas de Facebook)

📝 Apartado 2: Formulario de Publicación en Facebook

✍️

Formulario de Publicación (Muestra: formulario de publicación, botón "Publicar", vista previa)

FASE 1: Configuración de Facebook Developer (ACTUALIZADA 2026)

Objetivo: Registrar nuestra aplicación en Facebook para obtener credenciales de API (App ID y App Secret) que permitirán la comunicación entre nuestro sistema y Facebook.

⚠️ IMPORTANTE - Cambios en Facebook API 2026

  • 🚫 Facebook YA NO permite publicar en perfiles personales desde 2018 (política actual mantenida en 2026)
  • ✅ SOLUCIÓN: Usaremos Facebook Pages (Páginas) en modo Development
  • ✅ Ventajas del Modo Development:
    • 100% GRATIS (sin necesidad de verificación comercial)
    • NO requiere App Review ni documentación
    • Funciona con cuentas personales estándar
    • Hasta 5 usuarios testers (perfecto para evaluación académica)
    • Todos los permisos disponibles inmediatamente
  • 📝 Limitación: Solo usuarios agregados como "Testers" o "Administradores" pueden usar la app

Paso 1.1: Crear una Página de Facebook (NUEVO - OBLIGATORIO)

¿Por qué necesito una Página? Facebook bloqueó las publicaciones en perfiles personales vía API. Las Páginas son el único método permitido actualmente.

  1. Crear Página de Facebook:
    • Ve a: https://www.facebook.com/pages/create
    • Haz clic en "Empezar" o "Get Started"
    • Selecciona categoría: "Comunidad o figura pública" (recomendado para proyectos de prueba)
    • Nombre de la página: "UTH Servicios Web - Proyecto de Prueba" (o el que prefieras)
    • Categoría: Escribe "Educación" y selecciona de la lista
    • Haz clic en "Crear página"
    • ⚠️ IMPORTANTE: Guarda el nombre de tu página, lo necesitarás después
  2. Configuración básica de la Página:
    • Puedes omitir foto de perfil y portada por ahora
    • Haz clic en "Omitir" hasta terminar la configuración inicial
    • Tu página ya está creada y activa

Paso 1.2: Crear App en Facebook Developers (ACTUALIZADO 2026)

  1. Acceso a Facebook Developers:
    • Abre tu navegador y ve a https://developers.facebook.com
    • Inicia sesión con tu cuenta de Facebook personal
    • Si es tu primera vez, acepta los "Terms of Service" de desarrollador
    • Verifica tu cuenta si se solicita (puede requerir número de teléfono)
  2. Crear Nueva Aplicación (Proceso 2026):
    • Haz clic en "My Apps" (Mis Aplicaciones) en la esquina superior derecha
    • Haz clic en el botón verde "Create App" (Crear Aplicación)
    • PASO CRÍTICO - Selecciona el tipo correcto:
    • 📌 Selecciona: "None" o "Other" (para proyectos personales/educativos)
    • Si ves "Business", "Consumer", "Gaming" → Selecciona "Consumer"
    • Haz clic en "Next" (Siguiente)
  3. Configurar Detalles de la App (2026):
    • App Name: "UTH Facebook Integration 2026" (o nombre descriptivo)
    • App Contact Email: Tu correo personal o institucional VERIFICADO
    • App Purpose: Selecciona "Yourself or your own business"
    • Business Account (opcional): Selecciona "Create a new Business Account" o "Skip" si aparece
    • Haz clic en "Create App" (Crear Aplicación)
    • Completa el CAPTCHA de seguridad
    • ⚠️ Si pide verificación adicional: Verifica tu identidad siguiendo los pasos de Facebook
  4. Obtener Credenciales de API:
    • Una vez creada, serás redirigido al Dashboard de la app
    • En el menú lateral izquierdo, haz clic en "Settings" → "Basic"
    • Aquí encontrarás tus credenciales:
    • App ID:
      • Número único de 15-16 dígitos (ej: 1234567890123456)
      • 📋 CÓPIALO y guárdalo en un archivo de texto temporal
    • App Secret:
      • Haz clic en el botón "Show" (Mostrar)
      • Ingresa tu contraseña de Facebook para verificar
      • Código de 32 caracteres hexadecimales (ej: abc123def456...)
      • 🔐 CÓPIALO y guárdalo de forma SEGURA
      • ⚠️ NUNCA lo compartas públicamente ni lo subas a GitHub
  5. Configurar App Settings (ACTUALIZADO 2026):
    • Desplázate hacia abajo en "Basic Settings"
    • App Domains: Agrega localhost
    • Privacy Policy URL: Puedes dejarlo vacío para modo Development
    • Terms of Service URL: Puedes dejarlo vacío para modo Development
    • Haz clic en "Save Changes" al final de la página
  6. Agregar Producto Facebook Login (2026):
    • En el menú lateral izquierdo, busca la sección "Add Products"
    • Encuentra el producto "Facebook Login"
    • Haz clic en el botón "Set Up" (Configurar)
    • Selecciona plataforma: "Web" (www)
    • En el formulario que aparece:
    • Site URL: http://localhost:8000
    • Haz clic en "Save" (Guardar)
    • Puedes hacer clic en "Continue" o "Next" hasta finalizar el quickstart
  7. Configurar URLs de Redirección OAuth (CRÍTICO):
    • En el menú lateral, ve a "Facebook Login" → "Settings"
    • Desplázate hasta la sección "Valid OAuth Redirect URIs"
    • Agrega las siguientes URLs (una por línea):
    • http://localhost:8000/facebook/callback/
      http://127.0.0.1:8000/facebook/callback/
    • ⚠️ IMPORTANTE: Respeta EXACTAMENTE mayúsculas/minúsculas y la barra final "/"
    • Client OAuth Login: Activar ON (switch verde)
    • Web OAuth Login: Activar ON (switch verde)
    • Enforce HTTPS: Desactivar OFF para desarrollo local (switch gris)
    • Haz clic en "Save Changes" (Guardar Cambios) al final
  8. Configurar Modo de Desarrollo (ESENCIAL):
    • En la parte superior del Dashboard verás un interruptor "App Mode"
    • Asegúrate que esté en "Development" (Desarrollo)
    • Si está en "Live" (En vivo), haz clic para cambiarlo a "Development"
    • Ventaja: En modo Development NO necesitas App Review ni verificación comercial
    • 📝 Limitación: Solo tú y usuarios agregados como "Testers" pueden usar la app
  9. Agregar Permisos de Páginas (NUEVO 2026 - OBLIGATORIO PARA PUBLICAR):
    • En el menú lateral, ve a "App Review" → "Permissions and Features"
    • Busca y solicita los siguientes permisos (en modo Development se aprueban automáticamente):
      • pages_show_list - Listar páginas administradas
      • pages_read_engagement - Leer métricas de páginas
      • pages_manage_posts - PUBLICAR en páginas (el más importante)
      • pages_read_user_content - Leer contenido de páginas
    • En modo Development, estos permisos están disponibles inmediatamente
  10. Agregar Usuarios Testers (Opcional - para compartir con compañeros):
    • Ve a "Roles" → "Roles" en el menú lateral
    • En la sección "Testers", haz clic en "Add Testers"
    • Ingresa el nombre o correo de Facebook de tus compañeros
    • Ellos recibirán una invitación que deben aceptar en: developers.facebook.com/apps
    • 📝 Límite: Hasta 5 testers en cuenta gratuita
✅ Resultado de la Fase 1 (Actualizado 2026):
Ahora tienes una aplicación Facebook completamente configurada:
  • 📄 Página de Facebook creada (para publicaciones vía API)
  • 📌 App ID (identificador público de tu app: ej. 1234567890123456)
  • 🔐 App Secret (clave secreta - NUNCA compartir)
  • 🔗 OAuth Redirect URIs configuradas (localhost:8000/facebook/callback/)
  • Facebook Login activado con Client OAuth y Web OAuth
  • 📊 Permisos de Páginas habilitados:
    • pages_show_list (listar páginas)
    • pages_manage_posts (publicar en páginas)
    • pages_read_engagement (leer métricas)
  • Modo Development activo (100% gratis, sin verificación comercial)
  • 👥 Roles configurados (opcional: testers agregados)

💡 Diferencias clave 2026:
✅ NO necesitas verificación comercial en modo Development
✅ NO necesitas App Review para permisos de páginas
✅ Publicaciones funcionan SOLO en Páginas (no en perfiles personales)
✅ Hasta 5 usuarios testers sin costo adicional

✅ MODO DEVELOPMENT - Configuración Completa 2026

Tu app está en modo "Development" - ¡Esto es PERFECTO para proyectos universitarios!

🎯 Ventajas del Modo Development (2026):

  • ✅ 100% GRATIS - Sin costos, sin tarjeta de crédito
  • ✅ Sin verificación comercial - NO necesitas registrar empresa ni documento fiscal
  • ✅ Sin App Review - Los permisos de páginas se aprueban automáticamente en modo Development
  • ✅ Permisos completos - Acceso a:
    • public_profile (nombre, foto)
    • email (correo electrónico)
    • pages_show_list (listar páginas administradas)
    • pages_manage_posts (PUBLICAR en páginas)
    • pages_read_engagement (métricas y estadísticas)
    • pages_read_user_content (leer contenido)
  • ✅ Ideal para educación - Diseñado para aprendizaje y pruebas
  • ✅ Hasta 5 usuarios testers - Suficiente para equipos académicos y evaluación

📝 Única Limitación:

  • Solo usuarios autorizados pueden usar la app:
    • Tú (administrador de la app)
    • Usuarios agregados como "Developers" o "Testers" en Roles
    • Administradores de la Business Account (si configuraste una)
  • Publicaciones solo en Páginas: NO en perfiles personales (política de Facebook desde 2018, vigente en 2026)

🔄 ¿Cómo agregar más usuarios (testers)?

  1. Ve a developers.facebook.com
  2. Selecciona tu app → "Roles" (menú lateral)
  3. En la sección "Testers", haz clic en "Add Testers"
  4. Ingresa el nombre o email de Facebook de la persona
  5. Envía invitación → La persona debe aceptarla en developers.facebook.com/apps

❌ NO necesitas hacer esto (común error):

  • ❌ Cambiar a modo "Live" (no necesario para proyectos académicos)
  • ❌ Solicitar App Review (solo si quieres usuarios públicos ilimitados)
  • ❌ Verificar empresa o negocio
  • ❌ Proporcionar documentación legal o fiscal
  • ❌ Pagar por servicios o verificación

💡 Para proyectos de la UTH, el Modo Development es SUFICIENTE y RECOMENDADO

FASE 2: Configuración del Entorno de Desarrollo Django

Objetivo: Crear la estructura base del proyecto Django e instalar todas las dependencias necesarias para la integración con Facebook y MySQL.

Paso 2: Configurar Proyecto Django (DETALLADO PARA PRINCIPIANTES)

¿Qué haremos? Crear un proyecto Django desde cero, configurar un entorno virtual para aislar dependencias, e instalar todas las librerías necesarias.

🪟 Abrir la Terminal/Línea de Comandos

Windows:

  1. Presiona Win + R (tecla Windows + R)
  2. Escribe cmd y presiona Enter
  3. Se abrirá una ventana negra (símbolo del sistema)

Mac:

  1. Presiona Cmd + Espacio
  2. Escribe Terminal y presiona Enter

Linux:

  1. Presiona Ctrl + Alt + T
# ========================================
# PASO 2.1: NAVEGAR A LA CARPETA DE TRABAJO
# ========================================

# Verás algo como: C:\Users\TuNombre>  (Windows)
#                o  nombre@computadora:~$  (Mac/Linux)

# Windows - Navegar a Documentos:
cd Documentos
mkdir Proyectos_Django
cd Proyectos_Django

# Mac/Linux - Navegar a Documentos:
cd ~/Documents
mkdir Proyectos_Django
cd Proyectos_Django

# 💡 TIP: Para ver dónde estás, escribe:
#    Windows: cd
#    Mac/Linux: pwd

# ========================================
# PASO 2.2: INSTALAR DJANGO GLOBALMENTE (SOLO SI NO LO TIENES)
# ========================================

# Primero verifica si Django está instalado:
python -m django --version

# Si aparece un error "No module named django", instálalo:
pip install django

# Debe mostrar: Successfully installed django-X.X.X

# ========================================
# PASO 2.3: CREAR PROYECTO DJANGO
# ========================================

# Este comando crea toda la estructura del proyecto
django-admin startproject facebook_integration

# Deberías ver un mensaje confirmando la creación (sin errores)

# Entrar a la carpeta del proyecto:
cd facebook_integration

# Verificar que se creó correctamente:
# Windows:
dir

# Mac/Linux:
ls

# Deberías ver:
# - Una carpeta llamada 'facebook_integration'
# - Un archivo llamado 'manage.py'

# Estructura creada:
# facebook_integration/
# ├── facebook_integration/
# │   ├── __init__.py
# │   ├── settings.py      (Configuración principal)
# │   ├── urls.py          (Rutas principales)
# │   ├── wsgi.py          (Servidor de producción)
# │   └── asgi.py          (Servidor asíncrono)
# └── manage.py            (Comando principal de Django)

# PASO 2.3: Crear entorno virtual
# Un entorno virtual aísla las dependencias de este proyecto
# para evitar conflictos con otros proyectos Python
python -m venv venv

# PASO 2.4: Activar entorno virtual
# Windows (cmd):
venv\Scripts\activate

# Windows (PowerShell):
venv\Scripts\Activate.ps1

# Linux/Mac:
source venv/bin/activate

# Verás '(venv)' al inicio de tu línea de comandos, indicando que está activo

# PASO 2.5: Instalar dependencias (EXPLICADAS)
# Primero actualizamos pip (gestor de paquetes Python)
python -m pip install --upgrade pip

# Ahora instalamos cada paquete con su propósito:

# Django: Framework web principal
pip install django

# mysqlclient: Conector para comunicarse con MySQL desde Django
pip install mysqlclient

# requests: Librería para hacer peticiones HTTP (comunicarse con Facebook API)
pip install requests

# djangorestframework: Herramientas para crear APIs REST (opcional pero útil)
pip install djangorestframework

# django-cors-headers: Permite peticiones desde otros dominios (CORS)
pip install django-cors-headers

# PASO 2.6: Verificar instalación
pip list
# Deberías ver todas las dependencias instaladas con sus versiones

# PASO 2.7: Crear aplicación Django 'social_app'
# Una app es un módulo funcional dentro del proyecto
python manage.py startapp social_app

# Estructura de social_app creada:
# social_app/
# ├── migrations/          (Historial de cambios en BD)
# ├── __init__.py
# ├── admin.py            (Configuración del panel admin)
# ├── apps.py             (Configuración de la app)
# ├── models.py           (Modelos de datos/tablas)
# ├── tests.py            (Pruebas unitarias)
# └── views.py            (Lógica de vistas/controladores)

# PASO 2.8: Crear archivo requirements.txt para documentar dependencias
pip freeze > requirements.txt
# Este archivo permite instalar todas las dependencias en otro ambiente con:
# pip install -r requirements.txt
💡 ¿Por qué usar entorno virtual?
Imagina que tienes dos proyectos: uno usa Django 3.2 y otro Django 4.2. Sin entornos virtuales, ambos compartirían las mismas librerías instaladas globalmente, causando conflictos. Con venv, cada proyecto tiene su propio "espacio" con versiones independientes.

FASE 3: Configuración de Base de Datos MySQL

Objetivo: Crear una base de datos MySQL dedicada y conectarla con Django para almacenar usuarios, tokens de acceso y publicaciones de Facebook.

Paso 3: Configurar MySQL (DETALLADO)

¿Qué haremos? Crear una base de datos, configurar la conexión en Django y definir qué aplicaciones estarán activas en nuestro proyecto.

# ========================================
# PARTE 3.1: CREAR BASE DE DATOS EN MySQL
# ========================================

# Opción A: Desde línea de comandos MySQL
# Abre terminal y conecta a MySQL:
mysql -u root -p
# Ingresa tu contraseña de MySQL cuando se solicite

# Crear base de datos con soporte UTF-8 completo (emojis, caracteres especiales)
CREATE DATABASE facebook_integration_db 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

# Verificar que se creó correctamente
SHOW DATABASES;

# Salir de MySQL
EXIT;

# Opción B: Desde phpMyAdmin (MySQL Workbench, XAMPP)
# 1. Abre phpMyAdmin en tu navegador (http://localhost/phpmyadmin)
# 2. Clic en "Nueva" o "New" en el panel izquierdo
# 3. Nombre: facebook_integration_db
# 4. Cotejamiento: utf8mb4_unicode_ci
# 5. Clic en "Crear"

# ========================================
# PARTE 3.2: CONFIGURAR DJANGO
# ========================================

# Abre el archivo: facebook_integration/settings.py
# Busca la sección DATABASES y reemplázala con lo siguiente:
# ===== facebook_integration/settings.py =====

# CONFIGURACIÓN DE BASE DE DATOS
DATABASES = {
    'default': {
        # Motor de base de datos (MySQL)
        'ENGINE': 'django.db.backends.mysql',
        
        # Nombre de la base de datos que creamos
        'NAME': 'facebook_integration_db',
        
        # Usuario de MySQL (por defecto 'root')
        'USER': 'root',
        
        # Contraseña de MySQL (CAMBIA ESTO por tu contraseña real)
        'PASSWORD': 'tu_password_aqui',
        
        # Servidor donde está MySQL (local)
        'HOST': 'localhost',
        
        # Puerto por defecto de MySQL
        'PORT': '3306',
        
        # Opciones adicionales para el conector
        'OPTIONS': {
            'charset': 'utf8mb4',  # Soporte completo de Unicode
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",  # Validación estricta
        },
    }
}

# APLICACIONES INSTALADAS
# Esta lista define qué módulos están activos en Django
INSTALLED_APPS = [
    # Aplicaciones integradas de Django:
    'django.contrib.admin',          # Panel de administración
    'django.contrib.auth',           # Sistema de autenticación
    'django.contrib.contenttypes',   # Gestión de tipos de contenido
    'django.contrib.sessions',       # Manejo de sesiones
    'django.contrib.messages',       # Sistema de mensajes
    'django.contrib.staticfiles',    # Archivos estáticos (CSS, JS, imágenes)
    
    # Aplicaciones de terceros:
    'rest_framework',                # Django REST Framework (para APIs)
    'corsheaders',                   # Manejo de CORS para peticiones externas
    
    # Nuestra aplicación personalizada:
    'social_app',                    # App que creamos para Facebook
]

# MIDDLEWARE (procesadores de peticiones)
# Asegúrate de que CorsMiddleware esté ANTES de CommonMiddleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # ← Agregar CORS
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# CONFIGURACIÓN DE CORS (permitir peticiones desde otros dominios)
CORS_ALLOWED_ORIGINS = [
    "http://localhost:8000",
    "http://127.0.0.1:8000",
]

# CONFIGURACIÓN DE FACEBOOK
# Aquí pondremos las credenciales que obtuvimos de Facebook Developers
FACEBOOK_APP_ID = '123456789012345'  # ← Reemplaza con tu App ID real
FACEBOOK_APP_SECRET = 'abcdef0123456789abcdef0123456789'  # ← Reemplaza con tu App Secret
FACEBOOK_REDIRECT_URI = 'http://localhost:8000/facebook/callback/'

# IMPORTANTE: Nunca subas este archivo a repositorios públicos con credenciales reales
# En producción, usa variables de entorno:
# import os
# FACEBOOK_APP_ID = os.getenv('FACEBOOK_APP_ID')
# FACEBOOK_APP_SECRET = os.getenv('FACEBOOK_APP_SECRET')

# CONFIGURACIÓN DE ZONA HORARIA
TIME_ZONE = 'America/Hermosillo'  # Ajusta a tu zona horaria
USE_TZ = True

# CONFIGURACIÓN DE IDIOMA
LANGUAGE_CODE = 'es-mx'  # Español de México
⚠️ Seguridad Crítica:
  • 🔐 Nunca compartas tu FACEBOOK_APP_SECRET en repositorios públicos
  • 🔐 Cambia SECRET_KEY de Django antes de publicar
  • 🔐 En producción, usa variables de entorno en lugar de hardcodear credenciales
  • 🔐 Crea un archivo .env para credenciales locales y agrégalo a .gitignore
✅ Resultado de la Fase 3:
Django ahora puede:
  • ✨ Conectarse a MySQL para leer/escribir datos
  • ✨ Comunicarse con Facebook Graph API usando las credenciales configuradas
  • ✨ Gestionar peticiones CORS desde aplicaciones frontend
  • ✨ Utilizar todas las apps instaladas (admin, auth, social_app, etc.)

FASE 4: Diseño de Modelos de Datos (Tablas de Base de Datos)

Objetivo: Definir la estructura de datos que almacenaremos en MySQL mediante modelos Django. Crearemos dos tablas: una para cuentas de Facebook vinculadas y otra para publicaciones realizadas.

Paso 4: Crear Modelos (social_app/models.py)

¿Qué son los modelos? En Django, los modelos son clases Python que representan tablas en la base de datos. Django automáticamente convierte estas clases en tablas SQL con sus respectivas columnas.

# ===== social_app/models.py =====

from django.db import models
from django.contrib.auth.models import User  # Modelo de usuario integrado de Django

# ============================================
# MODELO 1: FacebookAccount (Cuentas de Facebook)
# ============================================
# Esta tabla almacenará la información de las cuentas Facebook vinculadas

class FacebookAccount(models.Model):
    """
    Representa una cuenta de Facebook conectada a un usuario de Django.
    Almacena el token de acceso y datos básicos del perfil.
    """
    
    # Relación uno-a-uno con el usuario de Django
    # Si se elimina el usuario, se elimina también su cuenta Facebook (CASCADE)
    user = models.OneToOneField(
        User, 
        on_delete=models.CASCADE,
        help_text="Usuario Django vinculado a esta cuenta Facebook"
    )
    
    # ID único de Facebook (ej: "1234567890123456")
    # unique=True asegura que no se dupliquen IDs
    facebook_id = models.CharField(
        max_length=100, 
        unique=True,
        help_text="ID numérico único asignado por Facebook"
    )
    
    # Token de acceso OAuth (permite hacer peticiones a Facebook API)
    # TextField porque puede ser muy largo (500+ caracteres)
    # ⚠️ En producción, este campo debería estar CIFRADO
    access_token = models.TextField(
        help_text="Token OAuth para autenticar peticiones a Facebook API"
    )
    
    # Información del perfil de Facebook
    nombre = models.CharField(
        max_length=200,
        help_text="Nombre completo del usuario en Facebook"
    )
    
    email = models.EmailField(
        blank=True,  # Puede estar vacío si Facebook no proporciona email
        help_text="Correo electrónico del usuario (si autorizó compartirlo)"
    )
    
    foto_perfil = models.URLField(
        blank=True,  # Puede estar vacío
        help_text="URL de la foto de perfil de Facebook"
    )
    
    # Metadatos
    fecha_vinculacion = models.DateTimeField(
        auto_now_add=True,  # Se establece automáticamente al crear el registro
        help_text="Fecha y hora en que se vinculó la cuenta"
    )
    
    # Configuración de metadatos del modelo
    class Meta:
        verbose_name = 'Cuenta de Facebook'
        verbose_name_plural = 'Cuentas de Facebook'
        ordering = ['-fecha_vinculacion']  # Ordenar por más recientes primero
    
    # Representación legible del objeto (se muestra en el admin de Django)
    def __str__(self):
        return f"{self.nombre} ({self.facebook_id})"
    
    # Método personalizado para verificar si el token ha expirado
    def token_valido(self):
        """Verifica si el access_token sigue siendo válido"""
        # En implementación real, aquí harías una petición a Facebook API
        # para verificar el token con /debug_token
        pass


# ============================================
# MODELO 2: FacebookPost (Publicaciones)
# ============================================
# Esta tabla almacenará las publicaciones realizadas desde nuestra app

class FacebookPost(models.Model):
    """
    Representa una publicación hecha en Facebook desde nuestra aplicación.
    Almacena contenido, métricas de interacción y metadatos.
    """
    
    # Relación muchos-a-uno: una cuenta puede tener múltiples posts
    # Si se elimina la cuenta, se eliminan también todos sus posts (CASCADE)
    account = models.ForeignKey(
        FacebookAccount, 
        on_delete=models.CASCADE,
        related_name='publicaciones',  # Permite acceder a posts desde account: account.publicaciones.all()
        help_text="Cuenta de Facebook que realizó la publicación"
    )
    
    # Contenido de la publicación
    mensaje = models.TextField(
        help_text="Texto del post publicado en Facebook"
    )
    
    # ID del post en Facebook (ej: "123456_789012")
    # Lo proporciona Facebook después de publicar exitosamente
    post_id = models.CharField(
        max_length=200, 
        blank=True,
        help_text="ID único del post asignado por Facebook (formato: user_id_post_id)"
    )
    
    # Metadatos temporales
    fecha_publicacion = models.DateTimeField(
        auto_now_add=True,
        help_text="Fecha y hora en que se publicó el post"
    )
    
    fecha_actualizacion = models.DateTimeField(
        auto_now=True,  # Se actualiza automáticamente cada vez que se guarda
        help_text="Última vez que se actualizaron las métricas"
    )
    
    # Métricas de interacción (se actualizan periódicamente)
    likes = models.IntegerField(
        default=0,
        help_text="Cantidad de 'Me gusta' del post"
    )
    
    comentarios = models.IntegerField(
        default=0,
        help_text="Cantidad de comentarios del post"
    )
    
    compartidos = models.IntegerField(
        default=0,
        help_text="Cantidad de veces que se compartió el post"
    )
    
    alcance = models.IntegerField(
        default=0,
        help_text="Número de personas únicas que vieron el post"
    )
    
    # Estado de la publicación
    ESTADO_CHOICES = [
        ('borrador', 'Borrador'),
        ('publicado', 'Publicado'),
        ('eliminado', 'Eliminado'),
        ('error', 'Error al publicar'),
    ]
    
    estado = models.CharField(
        max_length=20,
        choices=ESTADO_CHOICES,
        default='publicado',
        help_text="Estado actual de la publicación"
    )
    
    # Configuración de metadatos del modelo
    class Meta:
        verbose_name = 'Publicación de Facebook'
        verbose_name_plural = 'Publicaciones de Facebook'
        ordering = ['-fecha_publicacion']  # Más recientes primero
        indexes = [
            models.Index(fields=['-fecha_publicacion']),  # Índice para búsquedas rápidas
            models.Index(fields=['post_id']),
        ]
    
    def __str__(self):
        return f"Post: {self.mensaje[:50]}..." if len(self.mensaje) > 50 else f"Post: {self.mensaje}"
    
    # Método para calcular engagement (interacción total)
    @property
    def engagement_total(self):
        """Calcula la suma de todas las interacciones"""
        return self.likes + self.comentarios + self.compartidos
    
    # Método para calcular tasa de engagement
    @property
    def tasa_engagement(self):
        """Calcula el porcentaje de engagement respecto al alcance"""
        if self.alcance > 0:
            return round((self.engagement_total / self.alcance) * 100, 2)
        return 0.0
📊 Relación entre modelos:
User (Django)  ←→  FacebookAccount  ←  FacebookPost
    1        :        1          1  :    N (muchos)
    
Un usuario Django puede tener UNA cuenta Facebook
Una cuenta Facebook puede tener MUCHAS publicaciones
                
✅ Resultado de la Fase 4:
Hemos definido la estructura de datos que se convertirá en tablas SQL:
  • ✨ Tabla social_app_facebookaccount (perfiles vinculados)
  • ✨ Tabla social_app_facebookpost (publicaciones)
  • ✨ Campos con validaciones, índices y relaciones configuradas
  • ✨ Métodos personalizados para cálculos (engagement, validación de tokens)

FASE 5: Implementación de Lógica de Autenticación OAuth y Publicación

Objetivo: Crear las funciones (vistas) que manejarán el flujo de autenticación con Facebook, el callback de autorización y la publicación de contenido.

Paso 5: Crear Vistas (social_app/views.py)

¿Qué son las vistas? Son funciones Python que procesan peticiones HTTP (GET, POST) y devuelven respuestas. Aquí implementaremos el flujo OAuth completo.

# ===== social_app/views.py =====

import requests  # Para hacer peticiones HTTP a Facebook API
import json
from django.shortcuts import render, redirect  # Funciones de Django para renderizar templates y redirigir
from django.contrib.auth.decorators import login_required  # Decorador para proteger vistas que requieren login
from django.conf import settings  # Acceso a configuración de settings.py
from django.http import JsonResponse  # Para respuestas en formato JSON
from .models import FacebookAccount, FacebookPost  # Nuestros modelos
from django.contrib.auth.models import User

# ============================================
# VISTA 0: Página de Inicio (NUEVO)
# ============================================
def inicio(request):
    """
    Muestra la página principal con el botón de login con Facebook.
    Si el usuario ya está autenticado, lo redirige al dashboard.
    """
    # Verificar si el usuario ya tiene sesión activa
    if request.user.is_authenticated:
        return redirect('dashboard')
    
    # Mostrar página de login
    return render(request, 'login.html')

# ============================================
# VISTA 1: Iniciar Login con Facebook
# ============================================
def facebook_login(request):
    """
    Redirige al usuario a Facebook para que autorice nuestra aplicación.
    
    Flujo OAuth 2.0 - Paso 1: Authorization Request
    El usuario es enviado a Facebook donde verá qué permisos solicita nuestra app.
    """
    
    # Construir URL de autorización de Facebook
    # Esta es la URL a la que redirigiremos al usuario
    auth_url = "https://www.facebook.com/v18.0/dialog/oauth?"
    
    # Parámetro 1: client_id (nuestro App ID de Facebook)
    auth_url += f"client_id={settings.FACEBOOK_APP_ID}"
    
    # Parámetro 2: redirect_uri (dónde Facebook enviará al usuario después de autorizar)
    # DEBE coincidir EXACTAMENTE con la URL configurada en Facebook Developers
    auth_url += f"&redirect_uri={settings.FACEBOOK_REDIRECT_URI}"
    
    # Parámetro 3: scope (permisos que solicitamos)
    # email: acceso al correo electrónico
    # public_profile: nombre, foto de perfil, etc.
    # pages_show_list: listar páginas administradas
    # pages_read_engagement: leer métricas de páginas
    # pages_manage_posts: PUBLICAR en páginas (lo principal)
    auth_url += "&scope=email,public_profile,pages_show_list,pages_read_engagement,pages_manage_posts"
    
    # Parámetro 4: response_type (queremos un 'code' para intercambiar por token)
    auth_url += "&response_type=code"
    
    # Parámetro opcional: state (token CSRF para seguridad - recomendado en producción)
    # auth_url += f"&state={generate_random_state()}"
    
    # Redirigir al usuario a Facebook
    return redirect(auth_url)


# ============================================
# VISTA 2: Callback de Facebook (Procesar Autorización)
# ============================================
def facebook_callback(request):
    """
    Esta función se ejecuta cuando Facebook redirige al usuario de vuelta a nuestra app.
    
    Flujo OAuth 2.0 - Pasos 2 y 3:
    - Paso 2: Recibir código de autorización
    - Paso 3: Intercambiar código por access_token
    """
    
    # PASO 2.1: Obtener el código de autorización de la URL
    # Facebook envía el código como parámetro GET: ?code=ABC123...
    code = request.GET.get('code')
    
    # Si no hay código, significa que el usuario canceló la autorización
    # o hubo un error
    if not code:
        error_description = request.GET.get('error_description', 'Usuario canceló la autorización')
        return render(request, 'error.html', {
            'error': 'No se recibió código de autorización',
            'detalle': error_description
        })
    
    # PASO 2.2: Intercambiar código por access_token
    # Hacer petición POST a Facebook para obtener el token
    token_url = "https://graph.facebook.com/v18.0/oauth/access_token"
    
    params = {
        'client_id': settings.FACEBOOK_APP_ID,           # Nuestro App ID
        'client_secret': settings.FACEBOOK_APP_SECRET,   # Nuestro App Secret (¡secreto!)
        'redirect_uri': settings.FACEBOOK_REDIRECT_URI,  # Mismo redirect_uri del paso 1
        'code': code,                                     # Código recibido de Facebook
    }
    
    # Hacer la petición HTTP GET
    response = requests.get(token_url, params=params)
    token_data = response.json()  # Convertir respuesta JSON a diccionario Python
    
    # Verificar si hubo error
    if 'error' in token_data:
        return render(request, 'error.html', {
            'error': 'Error al obtener token de Facebook',
            'detalle': token_data.get('error_description', 'Error desconocido')
        })
    
    # Extraer el access_token de la respuesta
    access_token = token_data.get('access_token')
    
    # PASO 2.3: Obtener información del usuario usando el access_token
    # Consultar el endpoint /me de Graph API
    me_url = "https://graph.facebook.com/v18.0/me"
    
    user_params = {
        # 'fields': especifica qué información queremos obtener
        'fields': 'id,name,email,picture.type(large)',
        'access_token': access_token,  # Autenticación mediante token
    }
    
    user_response = requests.get(me_url, params=user_params)
    user_data = user_response.json()
    
    # Verificar si hubo error
    if 'error' in user_data:
        return render(request, 'error.html', {
            'error': 'Error al obtener datos del usuario',
            'detalle': user_data.get('error', {}).get('message', 'Error desconocido')
        })
    
    # PASO 2.4: Crear o actualizar usuario de Django y cuenta de Facebook
    # Primero, verificar si el usuario ya tiene cuenta en Django
    
    # Buscar si ya existe una cuenta Facebook con este ID
    try:
        facebook_account = FacebookAccount.objects.get(facebook_id=user_data['id'])
        # Si existe, actualizar el token (puede haber expirado el anterior)
        facebook_account.access_token = access_token
        facebook_account.nombre = user_data['name']
        facebook_account.email = user_data.get('email', '')
        facebook_account.foto_perfil = user_data['picture']['data']['url']
        facebook_account.save()
        
    except FacebookAccount.DoesNotExist:
        # Si no existe, crear nuevo usuario Django y cuenta Facebook
        
        # Verificar si el usuario ya está autenticado en Django
        if request.user.is_authenticated:
            django_user = request.user
        else:
            # Crear nuevo usuario Django
            username = f"fb_{user_data['id']}"  # Username único basado en FB ID
            django_user, created = User.objects.get_or_create(
                username=username,
                defaults={
                    'email': user_data.get('email', ''),
                    'first_name': user_data['name'].split()[0] if user_data['name'] else '',
                }
            )
        
        # Crear cuenta Facebook vinculada
        facebook_account = FacebookAccount.objects.create(
            user=django_user,
            facebook_id=user_data['id'],
            access_token=access_token,
            nombre=user_data['name'],
            email=user_data.get('email', ''),
            foto_perfil=user_data['picture']['data']['url'],
        )
    
    # PASO 2.5: Iniciar sesión del usuario en Django
    from django.contrib.auth import login
    login(request, facebook_account.user, backend='django.contrib.auth.backends.ModelBackend')
    
    # Redirigir al dashboard
    return redirect('dashboard')


# ============================================
# VISTA 3: Dashboard de Usuario
# ============================================
@login_required  # Solo usuarios autenticados pueden acceder
def dashboard(request):
    """
    Muestra el panel principal con información del usuario
    y sus publicaciones recientes.
    """
    
    try:
        # Obtener cuenta de Facebook del usuario actual
        facebook_account = FacebookAccount.objects.get(user=request.user)
        
        # Obtener últimas 10 publicaciones
        posts = FacebookPost.objects.filter(account=facebook_account)[:10]
        
        # Calcular estadísticas
        total_posts = FacebookPost.objects.filter(account=facebook_account).count()
        total_likes = sum(post.likes for post in posts)
        total_comentarios = sum(post.comentarios for post in posts)
        
        context = {
            'facebook_account': facebook_account,
            'posts': posts,
            'total_posts': total_posts,
            'total_likes': total_likes,
            'total_comentarios': total_comentarios,
        }
        
        return render(request, 'dashboard.html', context)
        
    except FacebookAccount.DoesNotExist:
        # Si el usuario no tiene cuenta Facebook vinculada, redirigir a login
        return redirect('facebook_login')


# ============================================
# VISTA 4: Publicar en Facebook
# ============================================
@login_required
def publicar_facebook(request):
    """
    Publica en una PÁGINA de Facebook (no en perfil personal).
    Facebook bloqueó publicaciones en perfiles personales desde 2018.
    """
    
    if request.method == 'POST':
        # Obtener mensaje del formulario
        mensaje = request.POST.get('mensaje', '').strip()
        
        # Validar que no esté vacío
        if not mensaje:
            return render(request, 'publicar.html', {
                'error': 'El mensaje no puede estar vacío'
            })
        
        try:
            # Obtener cuenta de Facebook del usuario
            account = FacebookAccount.objects.get(user=request.user)
            
            # PASO 4.1: Obtener lista de PÁGINAS administradas por el usuario
            pages_url = "https://graph.facebook.com/v18.0/me/accounts"
            pages_params = {
                'access_token': account.access_token,
            }
            
            pages_response = requests.get(pages_url, params=pages_params)
            pages_data = pages_response.json()
            
            # Verificar si hay error al obtener páginas
            if 'error' in pages_data:
                return render(request, 'publicar.html', {
                    'error': f"Error de Facebook: {pages_data['error']['message']}",
                    'detalle': 'Necesitas autorizar el permiso "pages_manage_posts"',
                    'solucion': 'Cierra sesión, vuelve a iniciar sesión con Facebook y autoriza todos los permisos.'
                })
            
            # Verificar si el usuario tiene páginas
            if not pages_data.get('data'):
                return render(request, 'publicar.html', {
                    'error': 'No administras ninguna Página de Facebook',
                    'detalle': 'Facebook ya NO permite publicar en perfiles personales.',
                    'solucion': 'Crea una Página de pruebas en: https://facebook.com/pages/create'
                })
            
            # PASO 4.2: Usar la primera página (puedes agregar selector después)
            primera_pagina = pages_data['data'][0]
            page_id = primera_pagina['id']
            page_access_token = primera_pagina['access_token']  # Token ESPECÍFICO de la página
            page_name = primera_pagina['name']
            
            # PASO 4.3: Publicar en la PÁGINA usando su access_token
            post_url = f"https://graph.facebook.com/v18.0/{page_id}/feed"
            
            data = {
                'message': mensaje,
                'access_token': page_access_token,  # ¡IMPORTANTE! Usar token de la PÁGINA
            }
            
            # Hacer petición POST a Facebook
            response = requests.post(post_url, data=data)
            post_data = response.json()
            
            # Verificar si hubo error al publicar
            if 'error' in post_data:
                error_message = post_data['error']['message']
                error_code = post_data['error'].get('code', 'N/A')
                error_type = post_data['error'].get('type', 'N/A')
                
                return render(request, 'publicar.html', {
                    'error': f"Error {error_code} ({error_type}): {error_message}",
                    'detalle': 'Revisa los permisos de tu app en Facebook Developers',
                    'json_response': json.dumps(post_data, indent=2)
                })
            
            # PASO 4.4: Guardar publicación en base de datos
            FacebookPost.objects.create(
                account=account,
                mensaje=mensaje,
                post_id=post_data.get('id', ''),
                estado='publicado',
            )
            
            # Construir URL del post para abrirlo
            post_facebook_url = f"https://www.facebook.com/{post_data.get('id', '').replace('_', '/posts/')}"
            
            # PASO 4.5: Mensaje de éxito
            return render(request, 'publicar.html', {
                'success': f'✅ ¡Publicación exitosa en la página "{page_name}"!',
                'post_id': post_data.get('id', ''),
                'page_name': page_name,
                'post_url': post_facebook_url,
                'nota': f'Se publicó en tu PÁGINA "{page_name}", no en tu perfil personal (Facebook lo bloqueó).'
            })
        
        except FacebookAccount.DoesNotExist:
            return redirect('facebook_login')
        
        except requests.exceptions.RequestException as e:
            return render(request, 'publicar.html', {
                'error': 'Error de conexión con Facebook',
                'detalle': str(e),
                'solucion': 'Verifica tu conexión a Internet y que Facebook esté disponible.'
            })
        
        except Exception as e:
            return render(request, 'publicar.html', {
                'error': f'Error inesperado: {type(e).__name__}',
                'detalle': str(e),
                'traza': 'Revisa los logs del servidor para más información.'
            })
    
    # Si es GET, mostrar formulario
    return render(request, 'publicar.html')


# ============================================
# VISTA 5: Obtener Métricas de un Post (API)
# ============================================
@login_required
def actualizar_metricas_post(request, post_id):
    """
    Actualiza las métricas (likes, comentarios, shares) de una publicación
    consultando la Graph API de Facebook.
    """
    
    try:
        # Obtener el post de la base de datos
        post = FacebookPost.objects.get(id=post_id, account__user=request.user)
        
        # Consultar métricas en Facebook
        insights_url = f"https://graph.facebook.com/v18.0/{post.post_id}"
        params = {
            'fields': 'reactions.summary(true),comments.summary(true),shares',
            'access_token': post.account.access_token,
        }
        
        response = requests.get(insights_url, params=params)
        metrics_data = response.json()
        
        # Actualizar métricas en base de datos
        post.likes = metrics_data.get('reactions', {}).get('summary', {}).get('total_count', 0)
        post.comentarios = metrics_data.get('comments', {}).get('summary', {}).get('total_count', 0)
        post.compartidos = metrics_data.get('shares', {}).get('count', 0)
        post.save()
        
        return JsonResponse({
            'success': True,
            'likes': post.likes,
            'comentarios': post.comentarios,
            'compartidos': post.compartidos,
        })
        
    except FacebookPost.DoesNotExist:
        return JsonResponse({'error': 'Post no encontrado'}, status=404)
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)
🔄 Flujo Completo de Autenticación OAuth 2.0:
1. Usuario hace clic en "Iniciar sesión con Facebook"
   → facebook_login() redirige a Facebook

2. Facebook muestra diálogo de permisos
   → Usuario autoriza aplicación

3. Facebook redirige a: /facebook/callback/?code=ABC123
   → facebook_callback() procesa código

4. App intercambia código por access_token
   → Petición a /oauth/access_token

5. App obtiene datos del usuario con el token
   → Petición a /me con access_token

6. App guarda usuario y token en MySQL
   → Crea FacebookAccount

7. Usuario es redirigido a dashboard
   → Puede publicar en Facebook
                
✅ Resultado de la Fase 5:
Hemos implementado todas las funciones clave:
  • ✨ Flujo OAuth completo (login → callback → token)
  • ✨ Creación/actualización automática de usuarios
  • ✨ Publicación de mensajes en Facebook
  • ✨ Actualización de métricas de interacción
  • ✨ Manejo de errores y validaciones

FASE 6: Creación de Templates HTML (INTERFAZ DE USUARIO)

Objetivo: Crear las páginas HTML que verá el usuario: login, dashboard, formulario de publicación y página de error.

📄 Templates HTML Listos para Copiar

¡Los 5 templates HTML están disponibles en un documento interactivo con botones de copiar!

📋 Abrir Documento de Templates Completos

Incluye: base.html, login.html, dashboard.html, publicar.html, error.html

Paso 6: Crear Templates (CARPETAS Y ARCHIVOS HTML)

¿Qué son los templates? Son archivos HTML con código dinámico de Django que muestran información al usuario.

📁 Estructura de Carpetas para Templates

Primero debes crear la estructura de carpetas:

facebook_integration/
├── facebook_integration/
├── social_app/
│   ├── templates/           ← CREAR ESTA CARPETA
│   │   ├── base.html        ← CREAR ESTE ARCHIVO
│   │   ├── login.html       ← CREAR ESTE ARCHIVO
│   │   ├── dashboard.html   ← CREAR ESTE ARCHIVO
│   │   ├── publicar.html    ← CREAR ESTE ARCHIVO
│   │   └── error.html       ← CREAR ESTE ARCHIVO
│   └── ...
└── manage.py
                

🛠️ ¿Cómo crear las carpetas y archivos?

Opción A: Desde Visual Studio Code (Recomendado)
  1. Abre VS Code
  2. Archivo → Abrir Carpeta → Selecciona facebook_integration
  3. En el explorador de la izquierda, busca la carpeta social_app
  4. Haz clic derecho sobre social_app → Nueva Carpeta → Escribe templates
  5. Haz clic derecho sobre templates → Nuevo Archivo → Escribe base.html
  6. Repite para crear: login.html, dashboard.html, publicar.html, error.html
Opción B: Desde Terminal (Todos los sistemas)
# Asegúrate de estar en la carpeta del proyecto (donde está manage.py)
# Windows:
cd facebook_integration
mkdir social_app\templates
type nul > social_app\templates\base.html
type nul > social_app\templates\login.html
type nul > social_app\templates\dashboard.html
type nul > social_app\templates\publicar.html
type nul > social_app\templates\error.html

# Mac/Linux:
cd facebook_integration
mkdir -p social_app/templates
touch social_app/templates/base.html
touch social_app/templates/login.html
touch social_app/templates/dashboard.html
touch social_app/templates/publicar.html
touch social_app/templates/error.html
                

📄 Template 1: base.html (Plantilla Base)

Este template contiene el código HTML común a todas las páginas (encabezado, estilos, pie de página).

<!-- ===== social_app/templates/base.html ===== -->

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Integración Facebook{% endblock %}</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #1877f2 0%, #42b72a 100%);
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            overflow: hidden;
        }
        header {
            background: linear-gradient(135deg, #1877f2 0%, #42b72a 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }
        header h1 { font-size: 2.5em; margin-bottom: 10px; }
        main { padding: 40px; min-height: 400px; }
        .btn {
            display: inline-block;
            background: #1877f2;
            color: white;
            padding: 15px 30px;
            text-decoration: none;
            border-radius: 8px;
            border: none;
            font-size: 16px;
            cursor: pointer;
            transition: background 0.3s;
        }
        .btn:hover { background: #42b72a; }
        .btn-facebook {
            background: #1877f2;
            padding: 12px 24px;
            font-size: 18px;
            font-weight: bold;
        }
        .btn-facebook:before { content: "📘 "; }
        footer {
            background: #2c3e50;
            color: white;
            text-align: center;
            padding: 20px;
        }
        .alert {
            padding: 15px;
            margin: 20px 0;
            border-radius: 8px;
            border-left: 5px solid;
        }
        .alert-success {
            background: #d4edda;
            border-color: #28a745;
            color: #155724;
        }
        .alert-error {
            background: #f8d7da;
            border-color: #dc3545;
            color: #721c24;
        }
        .form-group {
            margin-bottom: 20px;
        }
        .form-group label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
            color: #333;
        }
        .form-group textarea {
            width: 100%;
            min-height: 150px;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            font-family: inherit;
            resize: vertical;
        }
        .form-group textarea:focus {
            outline: none;
            border-color: #1877f2;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>🌐 {% block header %}Integración con Facebook{% endblock %}</h1>
            <p>Sistema de Gestión de Publicaciones Sociales</p>
        </header>
        
        <main>
            {% block content %}
            <!-- El contenido específico de cada página va aquí -->
            {% endblock %}
        </main>
        
        <footer>
            <p>© 2026 - Universidad Tecnológica de Hermosillo</p>
        </footer>
    </div>
</body>
</html>
            

📄 Template 2: login.html (Página de Inicio de Sesión)

<!-- ===== social_app/templates/login.html ===== -->

{% extends 'base.html' %}

{% block title %}Iniciar Sesión con Facebook{% endblock %}

{% block header %}Bienvenido al Sistema{% endblock %}

{% block content %}
<div style="text-align: center; padding: 50px 20px;">
    <h2 style="color: #1877f2; margin-bottom: 20px;">
        Conéctate con tu Cuenta de Facebook
    </h2>
    
    <p style="font-size: 18px; color: #666; margin-bottom: 40px; max-width: 600px; margin-left: auto; margin-right: auto;">
        Para utilizar este sistema, necesitas autorizar la conexión con tu cuenta de Facebook.
        Esto nos permitirá publicar contenido en tu nombre y obtener estadísticas de tus publicaciones.
    </p>
    
    <a href="{% url 'facebook_login' %}" class="btn btn-facebook">
        Iniciar Sesión con Facebook
    </a>
    
    <div style="margin-top: 40px; padding: 20px; background: #f0f2f5; border-radius: 10px; max-width: 500px; margin-left: auto; margin-right: auto;">
        <h3 style="color: #333; margin-bottom: 15px;">🔐 Seguridad y Privacidad</h3>
        <ul style="text-align: left; color: #666; line-height: 1.8;">
            <li>Solo solicitamos los permisos necesarios</li>
            <li>No almacenamos tu contraseña de Facebook</li>
            <li>Puedes revocar el acceso en cualquier momento</li>
            <li>Tu información está protegida con cifrado</li>
        </ul>
    </div>
</div>
{% endblock %}
            

📄 Template 3: dashboard.html (Panel Principal)

<!-- ===== social_app/templates/dashboard.html ===== -->

{% extends 'base.html' %}

{% block title %}Dashboard - {{ facebook_account.nombre }}{% endblock %}

{% block header %}Mi Dashboard{% endblock %}

{% block content %}
<div class="dashboard">
    <!-- Información del Usuario -->
    <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 12px; margin-bottom: 30px;">
        <div style="display: flex; align-items: center; gap: 20px;">
            <img src="{{ facebook_account.foto_perfil }}" 
                 alt="Foto de perfil" 
                 style="width: 100px; height: 100px; border-radius: 50%; border: 4px solid white;">
            <div>
                <h2 style="margin-bottom: 10px;">{{ facebook_account.nombre }}</h2>
                <p style="opacity: 0.9;">{{ facebook_account.email }}</p>
                <p style="opacity: 0.8; font-size: 14px;">
                    Conectado desde: {{ facebook_account.fecha_vinculacion|date:"d/m/Y H:i" }}
                </p>
            </div>
        </div>
    </div>
    
    <!-- Estadísticas Rápidas -->
    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px;">
        <div style="background: #e3f2fd; padding: 25px; border-radius: 12px; text-align: center;">
            <div style="font-size: 36px; color: #1877f2; font-weight: bold;">{{ total_posts }}</div>
            <div style="color: #666; margin-top: 10px;">Publicaciones Totales</div>
        </div>
        <div style="background: #fce4ec; padding: 25px; border-radius: 12px; text-align: center;">
            <div style="font-size: 36px; color: #e91e63; font-weight: bold;">{{ total_likes }}</div>
            <div style="color: #666; margin-top: 10px;">Me Gusta Totales</div>
        </div>
        <div style="background: #f3e5f5; padding: 25px; border-radius: 12px; text-align: center;">
            <div style="font-size: 36px; color: #9c27b0; font-weight: bold;">{{ total_comentarios }}</div>
            <div style="color: #666; margin-top: 10px;">Comentarios Totales</div>
        </div>
    </div>
    
    <!-- Acción Principal -->
    <div style="text-align: center; margin: 40px 0;">
        <a href="{% url 'publicar_facebook' %}" class="btn" style="padding: 20px 40px; font-size: 18px;">
            ✍️ Crear Nueva Publicación
        </a>
    </div>
    
    <!-- Lista de Publicaciones Recientes -->
    <h3 style="color: #333; margin: 30px 0 20px; font-size: 24px;">📋 Publicaciones Recientes</h3>
    
    {% if posts %}
        {% for post in posts %}
        <div style="background: #f8f9fa; padding: 20px; border-radius: 12px; margin-bottom: 15px; border-left: 5px solid #1877f2;">
            <p style="font-size: 16px; color: #333; margin-bottom: 15px;">{{ post.mensaje }}</p>
            
            <div style="display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 10px;">
                <span style="color: #666;">❤️ {{ post.likes }} Me gusta</span>
                <span style="color: #666;">💬 {{ post.comentarios }} Comentarios</span>
                <span style="color: #666;">🔄 {{ post.compartidos }} Compartidos</span>
            </div>
            
            <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 15px; padding-top: 15px; border-top: 1px solid #ddd;">
                <small style="color: #999;">{{ post.fecha_publicacion|date:"d/m/Y H:i" }}</small>
                <span style="padding: 5px 15px; background: #28a745; color: white; border-radius: 20px; font-size: 12px;">
                    {{ post.estado }}
                </span>
            </div>
        </div>
        {% endfor %}
    {% else %}
        <div style="text-align: center; padding: 60px 20px; background: #f8f9fa; border-radius: 12px;">
            <p style="font-size: 18px; color: #999;">
                📭 Aún no has realizado publicaciones.<br>
                <a href="{% url 'publicar_facebook' %}" style="color: #1877f2; text-decoration: underline;">
                    ¡Crea tu primera publicación ahora!
                </a>
            </p>
        </div>
    {% endif %}
</div>
{% endblock %}
            

📄 Template 4: publicar.html (Formulario de Publicación)

<!-- ===== social_app/templates/publicar.html ===== -->

{% extends 'base.html' %}

{% block title %}Publicar en Facebook{% endblock %}

{% block header %}Nueva Publicación{% endblock %}

{% block content %}
<div style="max-width: 700px; margin: 0 auto;">
    <h2 style="color: #1877f2; margin-bottom: 30px;">✍️ Crear Publicación en Facebook</h2>
    
    <!-- Mensajes de éxito o error -->
    {% if success %}
        <div class="alert alert-success">
            <strong>✅ {{ success }}</strong>
            {% if post_id %}
                <br><small>ID del post: {{ post_id }}</small>
            {% endif %}
        </div>
    {% endif %}
    
    {% if error %}
        <div class="alert alert-error">
            <strong>❌ {{ error }}</strong>
        </div>
    {% endif %}
    
    <!-- Formulario de publicación -->
    <form method="POST" action="{% url 'publicar_facebook' %}">
        {% csrf_token %}
        
        <div class="form-group">
            <label for="mensaje">Escribe tu mensaje:</label>
            <textarea 
                name="mensaje" 
                id="mensaje" 
                placeholder="¿Qué estás pensando?

Puedes escribir texto, emojis 🎉, hashtags #WebServices, y más..."
                required
                maxlength="5000"
            ></textarea>
            <small style="color: #999;">Máximo 5,000 caracteres</small>
        </div>
        
        <div style="display: flex; gap: 15px; justify-content: space-between; align-items: center;">
            <a href="{% url 'dashboard' %}" style="color: #666; text-decoration: none;">
                ← Volver al Dashboard
            </a>
            
            <button type="submit" class="btn" style="padding: 12px 30px;">
                📤 Publicar en Facebook
            </button>
        </div>
    </form>
    
    <!-- Consejos para publicaciones efectivas -->
    <div style="margin-top: 40px; padding: 25px; background: #f0f2f5; border-radius: 12px;">
        <h3 style="color: #333; margin-bottom: 15px;">💡 Consejos para publicaciones efectivas</h3>
        <ul style="color: #666; line-height: 1.8;">
            <li>Mantén el mensaje claro y conciso</li>
            <li>Usa emojis para hacerlo más atractivo 🚀</li>
            <li>Incluye hashtags relevantes #EducaciónDigital</li>
            <li>Haz preguntas para fomentar interacción</li>
            <li>Publica en horarios de mayor actividad (12-2pm, 7-9pm)</li>
        </ul>
    </div>
</div>
{% endblock %}
            

📄 Template 5: error.html (Página de Error)

<!-- ===== social_app/templates/error.html ===== -->

{% extends 'base.html' %}

{% block title %}Error - Integración Facebook{% endblock %}

{% block header %}Oops... Algo salió mal{% endblock %}

{% block content %}
<div style="text-align: center; padding: 50px 20px;">
    <div style="font-size: 80px; margin-bottom: 20px;">⚠️</div>
    
    <h2 style="color: #dc3545; margin-bottom: 20px;">{{ error }}</h2>
    
    {% if detalle %}
        <div style="background: #f8d7da; padding: 20px; border-radius: 10px; margin: 30px auto; max-width: 600px; border-left: 5px solid #dc3545;">
            <p style="color: #721c24; font-size: 16px; text-align: left;">
                <strong>Detalles del error:</strong><br>
                {{ detalle }}
            </p>
        </div>
    {% endif %}
    
    <div style="margin-top: 40px;">
        <a href="{% url 'facebook_login' %}" class="btn">
            🔄 Intentar Nuevamente
        </a>
    </div>
    
    <div style="margin-top: 50px; padding: 25px; background: #fff3cd; border-radius: 10px; max-width: 700px; margin-left: auto; margin-right: auto; text-align: left;">
        <h3 style="color: #856404; margin-bottom: 15px;">🛠️ Posibles soluciones:</h3>
        <ol style="color: #856404; line-height: 2;">
            <li>Verifica que la configuración de Facebook Developers sea correcta</li>
            <li>Asegúrate de que la URL de callback coincida exactamente</li>
            <li>Revisa que los permisos solicitados estén aprobados</li>
            <li>Confirma que el access token no haya expirado</li>
            <li>Verifica tu conexión a Internet</li>
        </ol>
    </div>
</div>
{% endblock %}
            
✅ Resultado de la Fase 6:
Templates HTML creados:
  • ✨ base.html - Plantilla base con diseño común
  • ✨ login.html - Página de inicio de sesión con Facebook
  • ✨ dashboard.html - Panel principal con estadísticas
  • ✨ publicar.html - Formulario para crear publicaciones
  • ✨ error.html - Página para mostrar errores amigables

💡 ¿Necesitas copiar los templates rápidamente?

📋 Ver Templates con Botones de Copiar

FASE 7: Configuración de Rutas URL

Objetivo: Mapear URLs a las vistas correspondientes para que Django sepa qué función ejecutar cuando el usuario accede a cada endpoint.

Paso 6: Configurar URLs (social_app/urls.py y proyecto principal)

¿Qué son las URLs en Django? Son patrones que asocian rutas web (ej: /facebook/login/) con funciones de vistas. Django las evalúa en orden y ejecuta la primera que coincida.

# ========================================
# PARTE 6.1: Crear archivo social_app/urls.py
# ========================================
# Este archivo define las rutas específicas de nuestra app social_app

from django.urls import path
from . import views  # Importar nuestras vistas

# Lista de patrones URL
urlpatterns = [
    # URL 0: Página de inicio (NUEVO)
    # Ruta raíz del sitio
    path('', views.inicio, name='inicio'),
    
    # URL 1: Iniciar login con Facebook
    # Cuando el usuario visita /facebook/login/
    # Django ejecuta views.facebook_login
    path('facebook/login/', views.facebook_login, name='facebook_login'),
    
    # URL 2: Callback de Facebook (donde redirige después de autorizar)
    # Facebook enviará al usuario a /facebook/callback/?code=ABC123
    # Django ejecuta views.facebook_callback
    path('facebook/callback/', views.facebook_callback, name='facebook_callback'),
    
    # URL 3: Dashboard principal del usuario
    # Muestra información del perfil y publicaciones
    path('dashboard/', views.dashboard, name='dashboard'),
    
    # URL 4: Formulario para publicar en Facebook
    # GET: muestra formulario | POST: procesa publicación
    path('facebook/publicar/', views.publicar_facebook, name='publicar_facebook'),
    
    # URL 5: API para actualizar métricas de un post específico
    #  captura el ID del post de la URL (ej: /facebook/post/123/metricas/)
    path('facebook/post//metricas/', 
         views.actualizar_metricas_post, 
         name='actualizar_metricas'),
]

# El parámetro 'name' permite referenciar estas URLs en templates:
# Iniciar sesión
# ========================================
# PARTE 6.2: Modificar facebook_integration/urls.py
# ========================================
# Este es el archivo de URLs principal del proyecto
# Incluye las URLs de todas las apps

from django.contrib import admin
from django.urls import path, include  # Agregar 'include'

urlpatterns = [
    # Panel de administración de Django
    # Accesible en: http://localhost:8000/admin/
    path('admin/', admin.site.urls),
    
    # Incluir todas las URLs de social_app
    # El segundo argumento '' significa que no hay prefijo adicional
    # Por eso facebook/login/ queda como http://localhost:8000/facebook/login/
    path('', include('social_app.urls')),
    
    # Si quisieras un prefijo, podrías hacer:
    # path('api/', include('social_app.urls'))
    # Entonces quedaría: http://localhost:8000/api/facebook/login/
]

# Estructura de URLs final:
# /admin/                          → Panel administración Django
# /facebook/login/                 → Iniciar login Facebook
# /facebook/callback/              → Callback OAuth Facebook
# /dashboard/                      → Dashboard del usuario
# /facebook/publicar/              → Publicar en Facebook
# /facebook/post//metricas/    → Actualizar métricas
🔗 ¿Cómo funcionan las URLs en Django?
  1. Usuario accede a http://localhost:8000/facebook/login/
  2. Django busca en facebook_integration/urls.py
  3. Encuentra path('', include('social_app.urls'))
  4. Busca en social_app/urls.py el patrón facebook/login/
  5. Encuentra match con path('facebook/login/', views.facebook_login)
  6. Ejecuta la función facebook_login() de views.py
  7. La función devuelve una respuesta (redirect, render, JsonResponse)
✅ Resultado de la Fase 7:
Rutas configuradas correctamente:
  • ✨ URLs mapeadas a vistas específicas
  • ✨ Nombres asignados para referenciar en templates
  • ✨ Parámetros dinámicos configurados (post_id)
  • ✨ Estructura modular (URLs de app separadas del proyecto)

🧪 CHECKPOINT: Verificación de Configuración (ANTES DE CONTINUAR)

Antes de seguir con las migraciones, asegúrate de que TODO esté configurado:

✓ Checklist de Archivos Creados:

facebook_integration/
├── facebook_integration/
│   ├── settings.py       ← Verificar configuración DATABASES y FACEBOOK_*
│   └── urls.py           ← Debe incluir path('', include('social_app.urls'))
├── social_app/
│   ├── models.py         ← Debe tener FacebookAccount y FacebookPost
│   ├── views.py          ← Debe tener inicio, facebook_login, facebook_callback, dashboard, publicar_facebook
│   ├── urls.py           ← Debe tener 6 rutas (inicio, login, callback, dashboard, publicar, metricas)
│   ├── admin.py          ← Debe registrar los modelos
│   └── templates/
│       ├── base.html
│       ├── login.html
│       ├── dashboard.html
│       ├── publicar.html
│       └── error.html
└── manage.py
                

✓ Verificar configuración de settings.py:

  1. DATABASES: Debe tener configuración de MySQL con tus credenciales
  2. INSTALLED_APPS: Debe incluir 'social_app', 'rest_framework', 'corsheaders'
  3. FACEBOOK_APP_ID: Reemplazado con tu App ID real de Facebook
  4. FACEBOOK_APP_SECRET: Reemplazado con tu App Secret real
  5. FACEBOOK_REDIRECT_URI: http://localhost:8000/facebook/callback/

✓ Probar que Django funciona (SIN BASE DE DATOS todavía):

# En la terminal, en la carpeta del proyecto:
python manage.py check

# Debe mostrar:
# System check identified no issues (0 silenced).
                

❌ Si hay errores:

  • "No module named 'social_app'": Verifica que 'social_app' esté en INSTALLED_APPS
  • "ModuleNotFoundError": Instala dependencias faltantes con pip install
  • Errores de sintaxis: Revisa cuidadosamente el código copiado

✅ Si NO hay errores, continúa con la Fase 8 (Migraciones)

FASE 8: Migración de Base de Datos y Creación de Superusuario

Objetivo: Convertir los modelos Python en tablas SQL reales en MySQL y crear un usuario administrador para acceder al panel de Django.

Paso 7: Migrar Base de Datos

¿Qué son las migraciones? Son archivos Python que describen cambios en la estructura de la base de datos (crear tablas, agregar columnas, etc.). Django las genera automáticamente desde los modelos y las aplica a MySQL.

# ========================================
# PASO 7.1: VERIFICAR CONEXIÓN A MySQL
# ========================================

# Primero asegúrate de que MySQL esté corriendo
# Windows: Abre "Servicios" (services.msc) y verifica que MySQL esté iniciado
# Linux/Mac: sudo systemctl status mysql

# Verificar conexión desde Django:
python manage.py dbshell

# Si conecta exitosamente, verás el prompt de MySQL:
# mysql>

# Salir:
# EXIT;

# ========================================
# PASO 7.2: CREAR ARCHIVOS DE MIGRACIÓN
# ========================================

# Este comando analiza models.py y detecta cambios
# Genera archivos en social_app/migrations/
python manage.py makemigrations

# Salida esperada:
# Migrations for 'social_app':
#   social_app/migrations/0001_initial.py
#     - Create model FacebookAccount
#     - Create model FacebookPost

# ¿Qué hace este comando?
# 1. Lee social_app/models.py
# 2. Compara con el estado anterior de la BD
# 3. Genera archivo Python (0001_initial.py) con instrucciones SQL
# 4. Este archivo describe cómo crear las tablas

# Ver contenido del archivo de migración (opcional):
# cat social_app/migrations/0001_initial.py  # Linux/Mac
# type social_app\migrations\0001_initial.py  # Windows

# ========================================
# PASO 7.3: APLICAR MIGRACIONES A MySQL
# ========================================

# Este comando ejecuta las migraciones en la base de datos
# Convierte los archivos .py en comandos SQL CREATE TABLE
python manage.py migrate

# Salida esperada:
# Operations to perform:
#   Apply all migrations: admin, auth, contenttypes, sessions, social_app
# Running migrations:
#   Applying contenttypes.0001_initial... OK
#   Applying auth.0001_initial... OK
#   Applying admin.0001_initial... OK
#   Applying sessions.0001_initial... OK
#   Applying social_app.0001_initial... OK

# ¿Qué hace este comando?
# 1. Lee todos los archivos de migración
# 2. Verifica cuáles ya fueron aplicados (tabla django_migrations)
# 3. Aplica solo las nuevas migraciones
# 4. Ejecuta SQL en MySQL:
#    CREATE TABLE social_app_facebookaccount (...)
#    CREATE TABLE social_app_facebookpost (...)

# Verificar tablas creadas en MySQL (opcional):
python manage.py dbshell

# En el prompt MySQL:
SHOW TABLES;

# Deberías ver:
# +-----------------------------+
# | Tables_in_fb_integration_db |
# +-----------------------------+
# | auth_user                   |
# | social_app_facebookaccount  |
# | social_app_facebookpost     |
# | django_migrations           |
# | ...                         |
# +-----------------------------+

# Ver estructura de una tabla:
DESCRIBE social_app_facebookaccount;

EXIT;

# ========================================
# PASO 7.4: CREAR SUPERUSUARIO (ADMIN)
# ========================================

# Este comando crea un usuario administrador
# Podrás acceder al panel /admin/ de Django
python manage.py createsuperuser

# El comando te pedirá:

# Username: admin
# (Presiona Enter o escribe un nombre de usuario)

# Email address: admin@example.com
# (Tu correo, puede ser ficticio en desarrollo)

# Password: ********
# (Escribe una contraseña segura, mínimo 8 caracteres)
# IMPORTANTE: La contraseña NO se muestra al escribir

# Password (again): ********
# (Repite la misma contraseña)

# Salida esperada:
# Superuser created successfully.

# ¿Para qué sirve el superusuario?
# - Acceder al panel de administración: http://localhost:8000/admin/
# - Gestionar usuarios, cuentas Facebook y posts desde interfaz web
# - Ver/editar/eliminar datos directamente sin SQL

# ========================================
# PASO 7.5: REGISTRAR MODELOS EN ADMIN
# ========================================

# Para que los modelos aparezcan en /admin/, edita social_app/admin.py:
# ===== social_app/admin.py =====

from django.contrib import admin
from .models import FacebookAccount, FacebookPost

# Configuración personalizada para FacebookAccount en el admin
@admin.register(FacebookAccount)
class FacebookAccountAdmin(admin.ModelAdmin):
    """Configuración del panel de administración para cuentas Facebook"""
    
    # Columnas que se muestran en la lista
    list_display = ('nombre', 'facebook_id', 'email', 'fecha_vinculacion')
    
    # Campos por los que se puede buscar
    search_fields = ('nombre', 'email', 'facebook_id')
    
    # Filtros laterales
    list_filter = ('fecha_vinculacion',)
    
    # Campos de solo lectura (no editables)
    readonly_fields = ('facebook_id', 'fecha_vinculacion', 'foto_perfil')
    
    # Orden por defecto
    ordering = ('-fecha_vinculacion',)

# Configuración personalizada para FacebookPost en el admin
@admin.register(FacebookPost)
class FacebookPostAdmin(admin.ModelAdmin):
    """Configuración del panel de administración para publicaciones"""
    
    list_display = ('mensaje_corto', 'account', 'likes', 'comentarios', 
                    'compartidos', 'estado', 'fecha_publicacion')
    
    search_fields = ('mensaje', 'post_id')
    
    list_filter = ('estado', 'fecha_publicacion', 'account')
    
    readonly_fields = ('post_id', 'fecha_publicacion', 'fecha_actualizacion', 
                       'engagement_total', 'tasa_engagement')
    
    ordering = ('-fecha_publicacion',)
    
    # Mostrar engagement total como campo calculado
    def mensaje_corto(self, obj):
        return obj.mensaje[:50] + '...' if len(obj.mensaje) > 50 else obj.mensaje
    mensaje_corto.short_description = 'Mensaje'
✅ Resultado de la Fase 8:
Base de datos configurada completamente:
  • ✅ Tablas creadas en MySQL:
    • social_app_facebookaccount (perfiles)
    • social_app_facebookpost (publicaciones)
    • auth_user (usuarios Django)
  • ✅ Relaciones y restricciones aplicadas (ForeignKey, OneToOne)
  • ✅ Superusuario creado para panel admin
  • ✅ Panel /admin/ configurado con vistas personalizadas

FASE 9: Ejecución y Pruebas del Sistema

Objetivo: Iniciar el servidor de desarrollo Django y probar todas las funcionalidades: autenticación, publicación y visualización de datos.

Paso 9: Probar el Sistema Localmente (GUÍA COMPLETA)

¿Qué vamos a probar? Todo el flujo desde el login hasta la publicación en Facebook, verificando que cada componente funcione correctamente.

# ========================================
# PASO 8.1: INICIAR SERVIDOR DE DESARROLLO
# ========================================

# Asegúrate de estar en la carpeta del proyecto (donde está manage.py)
# y con el entorno virtual activado (venv)

# Iniciar servidor Django:
python manage.py runserver

# Salida esperada:
# Watching for file changes with StatReloader
# Performing system checks...
#
# System check identified no issues (0 silenced).
# January 16, 2026 - 15:23:00
# Django version 4.2, using settings 'facebook_integration.settings'
# Starting development server at http://127.0.0.1:8000/
# Quit the server with CTRL-BREAK.

# El servidor ahora está corriendo en: http://localhost:8000

# ⚠️ IMPORTANTE: No cierres esta terminal, déjala abierta
# Si necesitas ejecutar otros comandos, abre otra terminal

# Para detener el servidor: Ctrl+C (Windows/Linux) o Cmd+C (Mac)
🧪 CHECKLIST DE PRUEBAS
# ========================================
# PRUEBA 1: Verificar Panel de Administración
# ========================================

# URL a probar: http://localhost:8000/admin/

# Pasos:
1. Abre el navegador (Chrome, Firefox, Edge)
2. Visita: http://localhost:8000/admin/
3. Verás el formulario de login de Django
4. Ingresa credenciales del superusuario:
   - Username: admin (o el que creaste)
   - Password: tu_password
5. Haz clic en "Log in"

# ✅ Resultado esperado:
- Panel de administración cargado
- Ver secciones: "Authentication and Authorization", "Social_App"
- En "Social_App" deberías ver:
  * Facebook Accounts (0 registros por ahora)
  * Facebook Posts (0 registros por ahora)

# ❌ Si hay error:
- Verifica que migraciones se aplicaron: python manage.py migrate
- Verifica credenciales del superusuario


# ========================================
# PRUEBA 2: Flujo de Autenticación con Facebook
# ========================================

# URL a probar: http://localhost:8000/facebook/login/

# Pasos:
1. Visita: http://localhost:8000/facebook/login/
2. Serás redirigido a Facebook (URL tipo: facebook.com/dialog/oauth?...)
3. Facebook mostrará diálogo: "Sistema de Integración Facebook UTH quiere acceder a:"
   - Tu nombre público y foto de perfil
   - Tu dirección de correo electrónico
   - Publicar en tu nombre
4. Haz clic en "Continuar como [Tu Nombre]" o "Continue"

# ✅ Resultado esperado:
- Redirigido a: http://localhost:8000/facebook/callback/?code=ABC123XYZ...
- Luego redirigido a: http://localhost:8000/dashboard/
- Dashboard muestra:
  * Tu nombre de Facebook
  * Tu foto de perfil
  * Botón "Publicar en Facebook"
  * Lista vacía de publicaciones (aún no has publicado)

# ❌ Si hay errores comunes:
- Error: "URL No Coincide"
  → Ve a Facebook Developers → Facebook Login → Settings
  → Verifica "Valid OAuth Redirect URIs": http://localhost:8000/facebook/callback/

- Error: "App No Disponible"
  → Ve a Facebook Developers → App Review
  → Verifica que el modo sea "Development" (permite testers)
  → Agrega tu cuenta Facebook como "Tester" en Roles → Testers

- Error: "Invalid Client Secret"
  → Verifica FACEBOOK_APP_SECRET en settings.py


# ========================================
# PRUEBA 3: Verificar Datos en MySQL
# ========================================

# Abrir MySQL y verificar que se guardó el usuario:
python manage.py dbshell

# Consultar cuenta Facebook creada:
SELECT * FROM social_app_facebookaccount;

# Deberías ver:
# +----+---------+--------------+-----------------+-------+------------------+
# | id | user_id | facebook_id  | access_token    | nombre| email            |
# +----+---------+--------------+-----------------+-------+------------------+
# | 1  | 1       | 123456789    | EAABwzLixn...   | Juan  | juan@example.com |
# +----+---------+--------------+-----------------+-------+------------------+

EXIT;

# ✅ Resultado esperado:
- Registro con tus datos de Facebook
- access_token largo (200+ caracteres)


# ========================================
# PRUEBA 4: Publicar en Facebook
# ========================================

# URL a probar: http://localhost:8000/facebook/publicar/

# Pasos:
1. Visita: http://localhost:8000/facebook/publicar/
2. Verás formulario con textarea para mensaje
3. Escribe un mensaje de prueba:
   "¡Hola desde mi aplicación Django integrada con Facebook! 🚀 #WebServices #UTH"
4. Haz clic en "Publicar"

# ✅ Resultado esperado:
- Mensaje de éxito: "¡Publicación realizada exitosamente en Facebook!"
- Muestra ID del post (ej: "1234567890_9876543210")
- Publicación aparece en tu muro de Facebook real
- Registro guardado en base de datos

# Verificar en Facebook:
5. Abre facebook.com en otra pestaña
6. Ve a tu perfil
7. Deberías ver la publicación que acabas de hacer

# Verificar en MySQL:
python manage.py dbshell
SELECT * FROM social_app_facebookpost;

# Deberías ver:
# +----+------------+---------+-----------+-------+------------+-------------+
# | id | account_id | mensaje | post_id   | likes | comentarios| estado      |
# +----+------------+---------+-----------+-------+------------+-------------+
# | 1  | 1          | ¡Hola...| 123_456   | 0     | 0          | publicado   |
# +----+------------+---------+-----------+-------+------------+-------------+

EXIT;


# ========================================
# PRUEBA 5: Panel de Administración - Gestionar Datos
# ========================================

# URL a probar: http://localhost:8000/admin/social_app/facebookpost/

# Pasos:
1. Ve al panel admin: http://localhost:8000/admin/
2. Haz clic en "Facebook posts"
3. Verás lista con tu publicación
4. Haz clic en la publicación para editarla
5. Intenta cambiar manualmente "likes" a 10
6. Guarda cambios

# ✅ Resultado esperado:
- Cambios guardados exitosamente
- Lista actualizada con nuevo valor


# ========================================
# PRUEBA 6: Actualizar Métricas desde Facebook
# ========================================

# URL a probar (API endpoint):
# http://localhost:8000/facebook/post/1/metricas/

# Opción A: Desde navegador
1. Ve a Facebook y dale "Me gusta" a tu publicación de prueba
2. Agrega 1-2 comentarios
3. Comparte el post
4. Visita: http://localhost:8000/facebook/post/1/metricas/
   (reemplaza '1' con el ID real de tu post)

# ✅ Resultado esperado:
- JSON con métricas actualizadas:
{
  "success": true,
  "likes": 1,
  "comentarios": 2,
  "compartidos": 1
}

# Opción B: Desde consola Python
python manage.py shell

from social_app.models import FacebookPost
post = FacebookPost.objects.first()
print(f"Post: {post.mensaje}")
print(f"Likes: {post.likes}")
print(f"Comentarios: {post.comentarios}")
print(f"Engagement: {post.engagement_total}")
print(f"Tasa: {post.tasa_engagement}%")

exit()


# ========================================
# RESUMEN DE PRUEBAS
# ========================================

✅ Panel admin funcional
✅ Login con Facebook exitoso
✅ Datos guardados en MySQL
✅ Publicación en Facebook desde app
✅ Post visible en Facebook real
✅ Métricas actualizables
✅ Panel admin muestra datos correctos
⚠️ Problemas Comunes y Soluciones
  • Error: "ModuleNotFoundError: No module named 'mysqlclient'"
    Solución: pip install mysqlclient
  • Error: "Access to localhost was denied"
    Solución: Verifica que MySQL esté corriendo y credenciales en settings.py
  • Error: "CSRF verification failed"
    Solución: Agrega {% csrf_token %} en formularios HTML
  • Error: "Invalid Scopes" en Facebook
    Solución: Ve a Facebook Developers → App Review → Solicita permisos avanzados
  • La publicación no aparece en Facebook
    Solución: Verifica que el access_token sea válido (puede expirar)
✅ Resultado de la Fase 9:
Sistema funcionando completamente:
  • 🎉 Servidor Django corriendo sin errores
  • 🎉 Autenticación OAuth con Facebook operativa
  • 🎉 Publicaciones en Facebook desde la app
  • 🎉 Datos almacenados correctamente en MySQL
  • 🎉 Panel de administración funcional
  • 🎉 Métricas de interacción actualizables

🚀 FASE 10: Despliegue en Producción - PythonAnywhere (OPCIONAL)

Objetivo: Publicar la aplicación en un servidor web en la nube para que sea accesible desde Internet con un dominio público.

¿Por qué PythonAnywhere?

Preparación Antes del Despliegue

# ========================================
# PASO 9.1: PREPARAR PROYECTO PARA PRODUCCIÓN
# ========================================

# Abrir facebook_integration/settings.py y modificar:

# 1. Agregar dominio de PythonAnywhere a ALLOWED_HOSTS
ALLOWED_HOSTS = [
    'localhost',
    '127.0.0.1',
    'tuusuario.pythonanywhere.com',  # ← Reemplaza 'tuusuario' con tu username real
]

# 2. Configurar DEBUG=False en producción (por ahora déjalo True para pruebas)
DEBUG = True  # Cambiar a False después de verificar que todo funciona

# 3. Configurar archivos estáticos
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# 4. Agregar import os al inicio del archivo
import os

# 5. Configurar variables de entorno para seguridad (recomendado)
# Crea un archivo .env en la raíz del proyecto (NO subir a GitHub):
# ===== Archivo .env (en la raíz del proyecto) =====
DEBUG=True
SECRET_KEY=tu-secret-key-de-django-muy-larga-y-segura
DATABASE_NAME=tuusuario$facebook_db
DATABASE_USER=tuusuario
DATABASE_PASSWORD=tu_password_mysql_pythonanywhere
DATABASE_HOST=tuusuario.mysql.pythonanywhere-services.com
FACEBOOK_APP_ID=123456789012345
FACEBOOK_APP_SECRET=abcdef0123456789abcdef0123456789
FACEBOOK_REDIRECT_URI=https://tuusuario.pythonanywhere.com/facebook/callback/

Despliegue Paso a Paso

# ========================================
# PASO 9.2: CREAR CUENTA EN PYTHONANYWHERE
# ========================================

1. Ve a: https://www.pythonanywhere.com
2. Haz clic en "Start running Python online in less than a minute!"
3. Selecciona "Create a Beginner account" (gratis)
4. Completa formulario:
   - Username: elige un nombre único (será tu subdominio)
   - Email: tu correo electrónico
   - Password: contraseña segura
5. Verifica tu email
6. Inicia sesión en PythonAnywhere


# ========================================
# PASO 9.3: CONFIGURAR BASE DE DATOS MySQL
# ========================================

1. En PythonAnywhere, ve a la pestaña "Databases"
2. En "Create a new database":
   - Database name: facebook_db
   - Haz clic en "Create"
3. Copia las credenciales mostradas:
   - Host: tuusuario.mysql.pythonanywhere-services.com
   - Database: tuusuario$facebook_db
   - Username: tuusuario
4. Establece una contraseña MySQL (diferente a la de tu cuenta)
5. Guarda estas credenciales (las necesitarás en settings.py)


# ========================================
# PASO 9.4: SUBIR CÓDIGO A PYTHONANYWHERE
# ========================================

# Opción A: Desde GitHub (recomendado)

# En tu computadora local:
# 1. Crea repositorio GitHub (si no tienes)
git init
git add .
git commit -m "Initial commit - Facebook integration project"
git remote add origin https://github.com/tuusuario/facebook-integration.git
git push -u origin main

# En PythonAnywhere:
# 2. Abre pestaña "Consoles" → "Bash"
# 3. Clona tu repositorio:
git clone https://github.com/tuusuario/facebook-integration.git
cd facebook-integration


# Opción B: Subir archivos manualmente
# 1. Ve a pestaña "Files" en PythonAnywhere
# 2. Navega a /home/tuusuario/
# 3. Crea carpeta: facebook-integration
# 4. Sube archivos uno por uno (tedioso, no recomendado para proyectos grandes)


# ========================================
# PASO 9.5: INSTALAR DEPENDENCIAS
# ========================================

# En Bash console de PythonAnywhere:

# Crear entorno virtual
mkvirtualenv --python=/usr/bin/python3.10 facebook_env

# Activar entorno virtual (automático después de crear)
workon facebook_env

# Instalar dependencias
pip install django mysqlclient requests djangorestframework django-cors-headers

# O si tienes requirements.txt:
pip install -r requirements.txt


# ========================================
# PASO 9.6: CONFIGURAR SETTINGS.PY PARA PRODUCCIÓN
# ========================================

# Editar facebook_integration/settings.py
# (usa editor web de Files o vim en Bash)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'tuusuario$facebook_db',  # ← Reemplaza tuusuario
        'USER': 'tuusuario',               # ← Reemplaza tuusuario
        'PASSWORD': 'tu_password_mysql',   # ← Tu contraseña MySQL de PythonAnywhere
        'HOST': 'tuusuario.mysql.pythonanywhere-services.com',  # ← Reemplaza
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
        },
    }
}

ALLOWED_HOSTS = ['tuusuario.pythonanywhere.com']

FACEBOOK_REDIRECT_URI = 'https://tuusuario.pythonanywhere.com/facebook/callback/'


# ========================================
# PASO 9.7: EJECUTAR MIGRACIONES
# ========================================

# En Bash console:
cd facebook-integration
python manage.py migrate

# Crear superusuario:
python manage.py createsuperuser

# Recolectar archivos estáticos:
python manage.py collectstatic


# ========================================
# PASO 9.8: CONFIGURAR WEB APP
# ========================================

1. Ve a pestaña "Web" en PythonAnywhere
2. Haz clic en "Add a new web app"
3. Selecciona dominio: tuusuario.pythonanywhere.com
4. Framework: "Manual configuration"
5. Python version: Python 3.10
6. Haz clic en "Next"

7. Configurar WSGI file:
   - En sección "Code", haz clic en "WSGI configuration file"
   - Borra TODO el contenido
   - Reemplaza con:
# ===== /var/www/tuusuario_pythonanywhere_com_wsgi.py =====

import os
import sys

# Ruta al proyecto
path = '/home/tuusuario/facebook-integration'
if path not in sys.path:
    sys.path.insert(0, path)

# Variables de entorno
os.environ['DJANGO_SETTINGS_MODULE'] = 'facebook_integration.settings'

# Activar entorno virtual
activate_this = '/home/tuusuario/.virtualenvs/facebook_env/bin/activate_this.py'
with open(activate_this) as file_:
    exec(file_.read(), dict(__file__=activate_this))

# Importar aplicación Django
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
# Continuar configuración Web App:

8. En sección "Virtualenv":
   - Virtualenv path: /home/tuusuario/.virtualenvs/facebook_env

9. En sección "Static files":
   - URL: /static/
   - Directory: /home/tuusuario/facebook-integration/staticfiles

10. Haz clic en botón verde "Reload tuusuario.pythonanywhere.com"


# ========================================
# PASO 9.9: ACTUALIZAR FACEBOOK DEVELOPERS
# ========================================

1. Ve a: https://developers.facebook.com
2. Selecciona tu app
3. Ve a "Facebook Login" → "Settings"
4. En "Valid OAuth Redirect URIs", AGREGA (no reemplaces):
   https://tuusuario.pythonanywhere.com/facebook/callback/
5. Guarda cambios


# ========================================
# PASO 9.10: PROBAR APLICACIÓN EN VIVO
# ========================================

1. Visita: https://tuusuario.pythonanywhere.com/facebook/login/
2. Deberías ver la redirección a Facebook
3. Autoriza la aplicación
4. Redirigido a dashboard
5. Prueba publicar un mensaje
6. Verifica que aparezca en Facebook

# Si hay errores:
- Revisa logs: Web → Log files → Error log
- Verifica credenciales MySQL
- Verifica ALLOWED_HOSTS en settings.py
- Verifica Facebook Redirect URI
🎉 ¡Aplicación Desplegada Exitosamente!
Tu sistema ahora está en producción:
  • ✅ Accesible desde Internet: https://tuusuario.pythonanywhere.com
  • ✅ Base de datos MySQL en la nube
  • ✅ Integración con Facebook funcionando
  • ✅ Panel admin: https://tuusuario.pythonanywhere.com/admin/

Mantenimiento y Actualizaciones

# Para actualizar código después de cambios:

# 1. En tu computadora local:
git add .
git commit -m "Descripción de cambios"
git push origin main

# 2. En PythonAnywhere Bash:
cd facebook-integration
git pull origin main
python manage.py migrate  # Si hay cambios en modelos
python manage.py collectstatic --noinput  # Si hay cambios en archivos estáticos

# 3. En pestaña Web:
# Haz clic en "Reload" para aplicar cambios

📖 Glosario de Términos Técnicos

Términos de Facebook API

  • OAuth 2.0: Protocolo estándar de autorización que permite a aplicaciones acceder a recursos de usuarios sin necesidad de sus contraseñas. Como dar una "llave temporal" en lugar de la llave maestra.
  • Access Token: Credencial temporal (cadena de texto) que permite acceso a recursos protegidos. Expira después de cierto tiempo por seguridad.
  • Graph API: API RESTful de Facebook para acceder al "social graph" (red social de conexiones entre usuarios, páginas, posts, etc.).
  • Scope/Permission: Permiso específico que solicita una app (ej: leer email, publicar posts). El usuario debe autorizar cada scope.
  • Node: Objeto individual en la Graph API (usuario, página, post, foto). Se accede mediante ID único.
  • Edge: Conexión entre nodos que representa relaciones (posts de un usuario, fotos de un álbum, amigos de una persona).
  • Field: Atributo específico de un nodo (nombre, email, fecha_creación). Se especifica en parámetro 'fields'.
  • Webhook: Notificación HTTP en tiempo real de eventos de Facebook (nuevo comentario, like, mensaje) enviada a tu servidor.
  • App ID: Identificador público único de tu aplicación Facebook (número de 15 dígitos).
  • App Secret: Clave secreta de tu aplicación Facebook. NUNCA debe compartirse públicamente.

Términos de Django

  • Model: Clase Python que representa una tabla en la base de datos. Django convierte automáticamente modelos en SQL.
  • View: Función o clase que procesa peticiones HTTP y devuelve respuestas (HTML, JSON, redirecciones).
  • Template: Archivo HTML con sintaxis especial de Django para insertar datos dinámicos.
  • URL Pattern: Patrón que mapea URLs a vistas específicas. Define las rutas de la aplicación.
  • Migration: Archivo Python que describe cambios en la estructura de la base de datos (crear tabla, agregar columna, etc.).
  • ORM (Object-Relational Mapping): Capa que permite interactuar con la base de datos usando objetos Python en lugar de SQL directo.
  • QuerySet: Conjunto de objetos obtenidos de la BD. Permite filtrar, ordenar y manipular datos.
  • Middleware: Componente que procesa todas las peticiones/respuestas antes de llegar a las vistas.
  • Admin Site: Panel de administración automático de Django para gestionar datos (/admin/).
  • settings.py: Archivo de configuración principal del proyecto (BD, apps instaladas, claves secretas).

Términos de Base de Datos

  • Primary Key (PK): Identificador único de cada registro en una tabla (generalmente campo 'id').
  • Foreign Key (FK): Campo que referencia la primary key de otra tabla. Crea relaciones entre tablas.
  • One-to-One: Relación donde un registro de tabla A se relaciona con exactamente un registro de tabla B.
  • One-to-Many: Relación donde un registro de tabla A puede tener múltiples registros en tabla B.
  • CASCADE: Comportamiento que elimina automáticamente registros relacionados cuando se elimina el registro principal.
  • Index: Estructura que acelera búsquedas en campos específicos de una tabla.
  • Charset (utf8mb4): Conjunto de caracteres que soporta emojis y caracteres especiales de todos los idiomas.

Términos de Desarrollo Web

  • HTTP GET: Método para solicitar datos del servidor (leer información).
  • HTTP POST: Método para enviar datos al servidor (crear/actualizar información).
  • JSON (JavaScript Object Notation): Formato de texto para intercambiar datos estructurados entre cliente y servidor.
  • API (Application Programming Interface): Conjunto de funciones y reglas para que aplicaciones se comuniquen entre sí.
  • Endpoint: URL específica de una API donde se accede a un recurso (ej: /api/users/).
  • CORS (Cross-Origin Resource Sharing): Mecanismo de seguridad que permite peticiones desde dominios diferentes.
  • CSRF (Cross-Site Request Forgery): Ataque web que Django previene con tokens especiales.
  • Redirect: Respuesta HTTP que envía al usuario a otra URL.
  • Status Code: Número que indica resultado de petición HTTP (200=OK, 404=No encontrado, 500=Error servidor).

🔐 Mejores Prácticas de Seguridad

Seguridad en Producción - CHECKLIST OBLIGATORIO

  1. Variables de Entorno:
    • ❌ NUNCA hardcodear credenciales en código
    • ✅ Usar variables de entorno para SECRET_KEY, DB_PASSWORD, API_KEYS
    • ✅ Usar librerías como python-decouple o django-environ
  2. DEBUG Mode:
    • DEBUG = False en producción SIEMPRE
    • ❌ DEBUG=True expone información sensible en errores
  3. Tokens de Acceso:
    • ✅ Cifrar access_tokens en base de datos usando django-fernet-fields
    • ✅ Implementar renovación automática de tokens expirados
    • ✅ Verificar validez de tokens antes de cada petición
  4. HTTPS:
    • ✅ Usar HTTPS en producción (PythonAnywhere lo proporciona automáticamente)
    • ✅ Configurar SECURE_SSL_REDIRECT = True
    • ✅ Configurar SESSION_COOKIE_SECURE = True
  5. Validación de Datos:
    • ✅ Validar TODOS los inputs del usuario
    • ✅ Usar Django Forms para validación automática
    • ✅ Sanitizar datos antes de guardar en BD
  6. Permisos de Facebook:
    • ✅ Solicitar solo los permisos necesarios
    • ✅ Explicar al usuario por qué necesitas cada permiso
    • ✅ Pasar App Review de Facebook para permisos avanzados
  7. Rate Limiting:
    • ✅ Implementar límites de peticiones para prevenir abuso
    • ✅ Usar django-ratelimit para controlar peticiones por IP

🆘 SOLUCIÓN DE PROBLEMAS (TROUBLESHOOTING)

Problemas Comunes y Sus Soluciones

❌ Error: "ModuleNotFoundError: No module named 'django'"

Causa: Django no está instalado o el entorno virtual no está activado.

Solución:

# 1. Verifica que el entorno virtual esté activado (deberías ver (venv) al inicio)
# 2. Si no está activado:
#    Windows: venv\Scripts\activate
#    Mac/Linux: source venv/bin/activate
# 3. Instala Django:
pip install django
                

❌ Error: "django.db.utils.OperationalError: (2003, "Can't connect to MySQL server")

Causa: MySQL no está corriendo o las credenciales son incorrectas.

Solución:

  1. Verificar que MySQL esté corriendo:
    • Windows: Servicios → MySQL80 → Iniciar
    • Mac: brew services start mysql
    • Linux: sudo systemctl start mysql
  2. Verificar credenciales en settings.py:
    DATABASES = {
        'default': {
            'NAME': 'facebook_integration_db',  # Debe existir
            'USER': 'root',                      # Tu usuario MySQL
            'PASSWORD': 'tu_password_real',      # Tu contraseña MySQL
            'HOST': 'localhost',
            'PORT': '3306',
        }
    }
                            
  3. Probar conexión manual:
    mysql -u root -p

    Si conecta, el problema está en settings.py

❌ Error: "ModuleNotFoundError: No module named 'mysqlclient'"

Causa: El conector MySQL para Python no está instalado.

Solución:

# Windows (puede requerir Visual C++ Build Tools):
pip install mysqlclient

# Si falla en Windows, usar alternativa:
pip install pymysql
# Luego agregar al inicio de settings.py:
import pymysql
pymysql.install_as_MySQLdb()

# Mac:
brew install mysql
pip install mysqlclient

# Linux:
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential
pip install mysqlclient
                

❌ Error de Facebook: "URL de Redirección No Válida"

Causa: La URL de callback no coincide exactamente con la configurada en Facebook Developers.

Solución:

  1. Ve a developers.facebook.com
  2. Selecciona tu app → Facebook Login → Settings
  3. En "Valid OAuth Redirect URIs" verifica que esté EXACTAMENTE:
    http://localhost:8000/facebook/callback/
  4. NO debe haber espacios, mayúsculas diferentes, o caracteres extra
  5. Guarda cambios y espera 1-2 minutos para que se apliquen

❌ Error: "CSRF verification failed"

Causa: Token CSRF faltante en formularios.

Solución:

Asegúrate que TODOS los formularios tengan:

<form method="POST">
    {% csrf_token %}  <!-- ESTA LÍNEA ES OBLIGATORIA -->
    ...
</form>
                

❌ Error: "TemplateDoesNotExist at /dashboard/"

Causa: Django no encuentra el template HTML.

Solución:

  1. Verifica estructura de carpetas:
    social_app/
    └── templates/
        ├── base.html
        ├── login.html
        ├── dashboard.html
        ├── publicar.html
        └── error.html
                            
  2. Verifica que settings.py tenga:
    INSTALLED_APPS = [
        ...
        'social_app',  # Debe estar aquí
    ]
                            

❌ El servidor inicia pero muestra "Page not found (404)"

Causa: URLs no configuradas correctamente.

Solución:

  1. Verifica facebook_integration/urls.py:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('social_app.urls')),  # Esta línea debe existir
    ]
                            
  2. Verifica social_app/urls.py exista y tenga las rutas
  3. Prueba acceder a: http://localhost:8000/ (sin subdirectorios)

❌ Error: "Invalid Scopes" al autorizar en Facebook

Causa: Los permisos solicitados no están aprobados para tu app.

Solución:

  1. Para desarrollo, usa solo permisos básicos:
    scope=email,public_profile
                            
  2. Para permisos avanzados (pages_manage_posts, user_posts):
    • Ve a Facebook Developers → App Review
    • Solicita permisos específicos
    • Proporciona documentación de uso
    • Espera aprobación (puede tardar días)

❌ Las publicaciones no aparecen en Facebook

Causas posibles:

  1. Token expirado:
    • Access tokens tienen tiempo de vida limitado
    • Solución: Volver a hacer login con Facebook
  2. Permisos insuficientes:
    • Verifica que el usuario autorizó "publicar en su nombre"
    • Revoca acceso en Facebook → Settings → Apps → Tu App → Eliminar
    • Vuelve a autorizar con todos los permisos
  3. App en modo Development:
    • Solo los testers agregados pueden ver publicaciones
    • Agrega usuarios en: App Dashboard → Roles → Testers

❌ Error: "Port 8000 is already in use"

Causa: Otro servidor Django está corriendo en ese puerto.

Solución:

  1. Opción 1: Detén el servidor anterior (Ctrl+C en la terminal)
  2. Opción 2: Usa otro puerto:
    python manage.py runserver 8080

    Luego accede a: http://localhost:8080

  3. Opción 3: Mata el proceso:
    • Windows: taskkill /F /IM python.exe
    • Mac/Linux: lsof -ti:8000 | xargs kill -9

❌ Migraciones fallan con "Table already exists"

Causa: Las tablas ya existen en MySQL de una ejecución anterior.

Solución:

# Opción 1: Resetear base de datos (BORRA TODOS LOS DATOS)
python manage.py dbshell
DROP DATABASE facebook_integration_db;
CREATE DATABASE facebook_integration_db CHARACTER SET utf8mb4;
EXIT;
python manage.py migrate

# Opción 2: Hacer fake de migraciones
python manage.py migrate --fake
                

❌ El panel /admin/ no muestra mis modelos

Causa: Los modelos no están registrados en admin.py.

Solución:

Verifica que social_app/admin.py tenga:

from django.contrib import admin
from .models import FacebookAccount, FacebookPost

@admin.register(FacebookAccount)
class FacebookAccountAdmin(admin.ModelAdmin):
    list_display = ('nombre', 'facebook_id', 'email')

@admin.register(FacebookPost)
class FacebookPostAdmin(admin.ModelAdmin):
    list_display = ('mensaje', 'likes', 'comentarios')
                

💡 CONSEJOS PARA EVITAR PROBLEMAS

Buenas Prácticas para Estudiantes

  1. 📝 Copia el código EXACTAMENTE:
    • Respeta mayúsculas y minúsculas
    • Copia comillas del mismo tipo (" o ')
    • Verifica la indentación (espacios vs tabs)
  2. 🧪 Prueba después de cada fase:
    • No avances si hay errores pendientes
    • Usa python manage.py check frecuentemente
  3. 💾 Guarda tu progreso:
    • Usa Git para control de versiones
    • Haz commits frecuentes: git commit -m "Fase X completada"
  4. 📖 Lee los errores completamente:
    • Django muestra mensajes de error detallados
    • La última línea suele indicar el problema
    • Google el error completo para encontrar soluciones
  5. 🔍 Usa el modo DEBUG:
    • En desarrollo, DEBUG = True es útil
    • Muestra errores detallados en el navegador
    • NUNCA uses DEBUG=True en producción
  6. 📚 Consulta documentación oficial:
  7. 👥 Pide ayuda:
    • Comparte el error completo con tu instructor
    • Usa Stack Overflow para problemas específicos
    • Trabaja en equipo con compañeros

📚 Recursos Adicionales para Profundizar

🎯 RESUMEN EJECUTIVO

¡Has Completado la Integración con Facebook! 🎉

10
Fases Completadas
5
Templates HTML
2
Modelos de Datos
6
Vistas Django

🏆 Competencias Desarrolladas

  • ✅ Integración de APIs REST de terceros
  • ✅ Implementación OAuth 2.0
  • ✅ Desarrollo Backend con Django
  • ✅ Diseño de bases de datos relacionales
  • ✅ Manejo de autenticación social
  • ✅ Consumo de Facebook Graph API
  • ✅ Desarrollo de interfaces web dinámicas
  • ✅ Gestión de variables de entorno
  • ✅ Despliegue de aplicaciones web
  • ✅ Debugging y troubleshooting

¡Felicitaciones por completar esta práctica avanzada de Servicios Web!

Ahora tienes las habilidades para integrar cualquier API externa en tus proyectos.

📞 ¿Necesitas Ayuda Adicional?

Si tienes problemas que no están cubiertos en esta guía:

  1. 💬 Grupo de clase: Comparte tu problema con compañeros
  2. 🔍 Stack Overflow: Busca el error exacto en Google
  3. 📚 Documentación oficial: Consulta la guía de Django/Facebook
  4. 🎥 YouTube: Busca tutoriales en video similares