Saltar al contenido

Capítulo 1 de 14

De una petición a una aplicación

Entender HTTP, separar proyecto y aplicación y seguir una petición real desde la terminal hasta una función Python.

#Qué problema resuelve un framework

Una aplicación web es un programa que otras personas utilizan enviándole mensajes. El navegador pide una página; el servidor decide qué puede mostrar, consulta datos y devuelve una respuesta. Django es un framework: proporciona una estructura y piezas coordinadas para resolver rutas, datos, formularios, usuarios y seguridad sin construir cada mecanismo desde cero. Tú escribes las reglas de tu producto dentro de esa estructura.

No necesitas conocer otro framework. Sí conviene distinguir tres cosas: Python ejecuta tu código, Django organiza la aplicación y un servidor recibe las conexiones HTTP. Al principio runserver combina lo necesario para desarrollar. Más adelante separaremos servidor de aplicación, proxy y base de datos para desplegar.

Recorrido HTTP: navegador envía GET, servidor entrega la petición a rutas y view; esta consulta datos y construye HTML; la respuesta vuelve al navegador.Ampliar diagrama ↗

Este curso usa Django 5.2 LTS y Python 3.12 o 3.13. LTS significa una serie con mantenimiento prolongado; no significa que puedas olvidarte de sus actualizaciones. Se mantiene el rango 5.2 para que las APIs explicadas sean coherentes, y al operar una aplicación se instalan sus parches de seguridad. Política y versiones soportadas.

#Leer HTTP antes de escribir una view

Una petición tiene un método, una ruta, cabeceras y, a veces, un cuerpo. GET /articulos/?pagina=2 pide una representación; POST /articulos/nuevo/ envía una acción o datos. La parte ?pagina=2 no es parte del patrón de ruta: son parámetros de consulta. Una cabecera como Accept: text/html expresa qué formato acepta el cliente. El cuerpo contiene, por ejemplo, campos de un formulario.

La respuesta tiene un código de estado, cabeceras y un cuerpo. 200 significa éxito; 302 envía a otra URL mediante Location; 404 indica que no se encuentra el recurso y 500, un fallo no resuelto del servidor. Content-Type: text/html indica cómo interpretar el cuerpo. Un 200 con una página que dice «error» no equivale a un error HTTP: las herramientas necesitan que ambos sean coherentes.

GET no debe crear ni borrar datos de negocio: navegadores, buscadores y caches pueden repetirlo. POST no garantiza que una acción ocurra una sola vez; un usuario puede hacer doble clic o repetir una petición tras un corte. Resolveremos esa diferencia cuando haya escrituras concurrentes.

#Un entorno que puedes volver a construir

Desde una carpeta de trabajo, ejecuta los comandos uno a uno. Esta primera práctica es una pequeña web de artículos; el proyecto final tendrá su propia carpeta y dominio de reservas.

mkdir web-articulos
cd web-articulos
python3 -m venv .venv
source .venv/bin/activate
python -m pip install 'Django>=5.2,<5.3'
python -m django startproject config .
python manage.py startapp articulos

venv crea un entorno con sus propios paquetes. Activarlo hace que python apunte a ese entorno en esta terminal. python -m pip instala con el mismo intérprete que utilizarás para ejecutar. En PowerShell usa py -m venv .venv y .venv\Scripts\Activate.ps1; después puedes usar python igual que aquí.

startproject config . crea la configuración del sitio en la carpeta actual; el punto evita una carpeta exterior adicional. startapp articulos prepara un paquete Python para una responsabilidad del sitio. Una aplicación no es un proceso separado ni un microservicio: muchas aplicaciones pueden convivir dentro del mismo proyecto y proceso.

Pieza Pregunta que responde
manage.py ¿Cómo ejecuto un comando con la configuración de este proyecto?
config/settings.py ¿Qué aplicaciones, base, idioma y políticas utiliza?
config/urls.py ¿Qué función recibe cada ruta inicial?
articulos/views.py ¿Qué devuelve una petición de artículos?
articulos/models.py ¿Qué información persistimos y con qué restricciones?
articulos/migrations/ ¿Cómo evoluciona esa estructura en bases existentes?

En config/settings.py, añade "articulos" al final de INSTALLED_APPS, conservando las entradas existentes. Cambia LANGUAGE_CODE = "es" y TIME_ZONE = "Europe/Madrid"; conserva USE_TZ = True. Las fechas internas y su presentación no son lo mismo: volveremos a ello con las reservas. Mantén por ahora la base SQLite generada; funciona como archivo local sin servidor adicional.

#Conectar las piezas sin magia

Sustituye articulos/views.py por esta función:

from django.http import HttpResponse


def listado(request):
    return HttpResponse("La sección de artículos responde.")

Una view es una función que recibe un objeto de petición y devuelve un objeto de respuesta. Django crea request y lo pasa al llamar a tu función. HttpResponse convierte el texto en una respuesta con estado 200. Aquí no hay modelo ni template: aislar la ruta permite saber qué parte funciona antes de añadir datos.

Crea articulos/urls.py; startapp no lo genera:

from django.urls import path
from . import views

app_name = "articulos"
urlpatterns = [
    path("", views.listado, name="listado"),
]

El punto de . import views importa desde este mismo paquete. Se pasa views.listado sin paréntesis: quieres entregar una función para usarla después, no ejecutarla al iniciar el proceso. name identifica la ruta sin obligarte a repetir su texto por toda la aplicación; app_name agrupa esos nombres.

Sustituye config/urls.py:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("articulos/", include("articulos.urls")),
]

Para /articulos/, la primera coincidencia consume articulos/ y include entrega el resto —una cadena vacía— a las rutas de esa aplicación. Django no busca por sí mismo una función que se llame como la URL.

#Observar una petición completa

Desde la carpeta que contiene manage.py:

python manage.py migrate
python manage.py runserver 127.0.0.1:8000

migrate crea las tablas de usuarios, sesiones y otras aplicaciones incorporadas. Todavía no has definido tablas propias. El servidor ocupa la terminal; abre otra, o detén con Ctrl+C cuando necesites cambiar de comando. En la otra terminal:

curl -i http://127.0.0.1:8000/articulos/
curl -i http://127.0.0.1:8000/no-existe/

curl es un cliente HTTP de terminal; -i muestra las cabeceras junto al cuerpo. Esperas un 200 con la frase y un 404 en la segunda dirección. En el navegador, http://127.0.0.1:8000/articulos/ muestra el mismo contenido. 127.0.0.1 significa esta máquina; no estás publicando el servicio en Internet.

El log del servidor debe mostrar método, ruta y estado. Cambia la frase, guarda y recarga. El autoreloader reinicia el código al detectarlo: es comodidad de desarrollo, no persistencia de estado. Una variable global que guardase artículos desaparecería al reiniciar y sería distinta entre varios procesos.

#Diagnosticar según dónde se rompe

Síntoma Qué comprobar primero Por qué
No conecta Proceso en marcha y puerto correcto Django aún no recibió la petición
404 en / No hemos definido esa ruta El servidor funciona, falta una coincidencia
Error de importación Nombre de paquete, entorno activo, fichero guardado El proyecto no logra cargar su código
no such table Migraciones aplicadas en esa base El código y la estructura persistente no coinciden
500 al abrir una ruta Traceback en la terminal de desarrollo Hay una excepción durante el procesamiento

Lee el traceback desde el tipo y mensaje final hacia la primera línea de tu código implicada. No soluciones cualquier fallo borrando db.sqlite3: podrías ocultar una migración incorrecta y perder datos que necesitabas conservar.

Comprobación: explica por qué la URL /articulos/ funciona aunque el fichero se llame views.py, y por qué un cambio en una variable Python no equivale a guardar en una base. El siguiente capítulo separa parámetros, métodos y respuestas sin añadir todavía nuevas dependencias.

    ↑ ↓ para recorrer · Intro para abrir · Ctrl K para buscar