Saltar al contenido

# creacion-de-aplicaciones-web-en-django-y-python

Creación de Aplicaciones Web en Django y Python

Volver a la portada del curso
Notebook

Integración Frontend y Backend

Sección 5 · Proyecto Final

Notebook: integración frontend y backend

El catálogo de PyShop ya responde en dos formatos: páginas HTML que arma Django y datos JSON en /api/productos/. Esta guía acompaña al notebook tienda-pyshop-completa, que une las dos mitades: la plantilla base con sus archivos estáticos, un archivo JavaScript que pide el JSON con fetch y lo pinta en la página, pruebas automáticas y la preparación para producción. También sirve como referencia del proyecto final.

Instalación y apertura

python -m venv .venv
.venv\Scripts\activate          # Windows
source .venv/bin/activate       # Linux y macOS
pip install "django==5.2.*" jupyter
jupyter notebook

El curso usa Django 5.2.18 con Python 3.13. La primera celda crea el proyecto completo en una carpeta temporal con datos.preparar (archivos, migraciones y datos de ejemplo). El notebook no abre un navegador: el JavaScript se escribe en un archivo y lo que se verifica con el cliente de pruebas es el JSON que ese código va a recibir.

Objetivos

  • Ubicar cada capa de la aplicación en sus archivos.
  • Servir CSS y JavaScript como archivos estáticos.
  • Consumir un endpoint JSON desde el frontend.
  • Agregar un filtro nuevo a la API y probarlo.
  • Escribir pruebas con TestCase y preparar la configuración de producción.

1. Mapa de la aplicación

El notebook lista los archivos del proyecto y los agrupa por capa: modelos y migraciones; vistas y formularios; rutas; plantillas; estáticos. Es el mismo orden de la lectura «Construcción de un backend».

2. Plantilla base y archivos estáticos

base.html empieza con {% load static %} y enlaza la hoja de estilos con {% static 'css/pyshop.css' %}. La etiqueta arma la ruta a partir de STATIC_URL (static/), así que cambiar dónde se sirven los estáticos no obliga a tocar las plantillas. Los archivos propios del proyecto viven en la carpeta static/ (STATICFILES_DIRS); los de cada app, en su propia carpeta static/.

3. La API y el JavaScript que la consume

El frontend pide los datos y los convierte en elementos de la página. El archivo JavaScript sigue esta idea:

fetch("/api/productos/")
  .then((respuesta) => respuesta.json())
  .then((datos) => {
    const lista = document.querySelector("#productos");
    for (const p of datos.productos) {
      const li = document.createElement("li");
      li.textContent = `${p.nombre} · $${p.precio}`;
      lista.appendChild(li);
    }
  });

El contrato entre las dos mitades es la forma del JSON: una clave productos con objetos que tienen nombre, categoria, precio y url. El notebook lo comprueba con Client: 200, tipo application/json, 7 productos, y el primero es la Gorra PyShop con precio 249.0. Usar textContent en lugar de innerHTML evita que un nombre con etiquetas HTML se interprete como código.

4. Un filtro nuevo en la API

El notebook amplía api_productos para aceptar ?categoria= y ?max_precio=, igual que la lista HTML filtra por categoría. Con los datos de ejemplo, ?categoria=ropa devuelve 3 productos (Gorra, Playera y Sudadera) y un precio máximo de 300 deja 4 (Gorra, Playera, Stickers y Taza). Observa cómo se valida el parámetro: llega como texto y hay que convertirlo antes de filtrar.

5. Consultas eficientes

Con CaptureQueriesContext se cuentan las consultas SQL de una operación. Recorrer los 7 productos disponibles leyendo su categoría cuesta 8 consultas sin select_related y 1 con él. Por eso tanto la lista como la API usan select_related("categoria").

6. Pruebas automáticas

El notebook escribe al menos 6 pruebas con TestCase y las ejecuta desde la propia celda. Cubren casos como estos: la lista responde 200, el filtro por categoría devuelve 3, el detalle de un producto inexistente da 404, la reseña sin sesión redirige al login (302), un POST válido con sesión crea la reseña y la API devuelve JSON. Todas deben pasar. Cada prueba corre sobre una base de datos de prueba que se crea y se destruye sola.

7. Preparar producción

La configuración lee DJANGO_DEBUG, DJANGO_SECRET_KEY y DJANGO_ALLOWED_HOSTS de variables de entorno. Con DJANGO_DEBUG=0 y DJANGO_ALLOWED_HOSTS=pyshop.example.com, python manage.py check --deploy da 5 advertencias:

  • security.W004: falta HSTS (SECURE_HSTS_SECONDS).
  • security.W008: no se redirige a HTTPS (SECURE_SSL_REDIRECT).
  • security.W009: la SECRET_KEY es débil.
  • security.W012: la cookie de sesión no es solo HTTPS (SESSION_COOKIE_SECURE).
  • security.W016: la cookie CSRF no es solo HTTPS (CSRF_COOKIE_SECURE).

Con una SECRET_KEY larga y aleatoria quedan 4: desaparece W009. Las otras dependen de servir el sitio con HTTPS.

8. collectstatic y el servidor WSGI

En producción, Django no sirve los estáticos: collectstatic --noinput los copia a STATIC_ROOT (staticfiles/) para que los sirva el servidor web. Con el proyecto base se copian 128 archivos, casi todos del admin más css/pyshop.css; cada archivo que agregues a static/ suma uno. La aplicación se ejecuta con un servidor WSGI, como Gunicorn, que carga pyshop.wsgi.application.

Ejercicios

Los ejercicios se comprueban con assert y tienen soluciones al final.

Qué observar

  • El JSON es un contrato: si cambias una clave, el JavaScript deja de funcionar aunque las pruebas de HTML pasen.
  • Las advertencias de check --deploy no aparecen en desarrollo: hay que pedirlas.
  • Un número de consultas que crece con los datos indica que falta select_related.

Recursos