MovieTracker: la app que construyes tú, funcionando en internet | El Pythonista

Tu primera app real.
Tuya. En internet. Ahora mismo.

Antes de leer una línea más, abre la demo. Entra con pedro / pedro-pythonista-2026, busca una película, guárdala. Lo que acadas de usar lo vas a haber escrito tú. Línea a línea. Desde la primera variable.

API REST en Flask Base de datos real Desplegada en internet
Pruébala ahora mismo — usuario pedro · contraseña pedro-pythonista-2026

Abre la demo antes de leer esto. En serio.

Date dos minutos. Entra con pedro / pedro-pythonista-2026, busca una película, guárdala en favoritos, mira las recomendaciones. No te lo estamos contando: te lo estamos enseñando funcionando.

Ahora piensa una cosa: ese código lo vas a haber escrito tú. Cada ruta, cada consulta a la base de datos, cada token de login. Línea a línea. Sin copiar. Sin trucos.

El curso no te enseña Python "por si algún día lo necesitas". Te lleva de tu primera variable hasta esta app en un servidor real con su dominio. Lo que acabas de ver funcionando es exactamente adónde vas a llegar. Abajo tienes cada pieza y el módulo donde la montas tú.

Las seis piezas que ya viste funcionando. Ahora te cuento para qué sirven.

Seis features reales. No lo que hacen técnicamente, sino para qué te sirven cuando las hayas construido tú.

Búsqueda de películas

El usuario escribe un título y la app le devuelve resultados reales: año, rating, director. Para que sepas conectar tu backend con cualquier servicio externo del mercado, que es exactamente lo que te piden en un trabajo real.

Qué aprendes construyéndola

A consumir una API externa de cine (OMDB) desde Python con requests: mandar la petición, controlar errores con raise_for_status() y parsear el JSON que devuelve. Lo mismo que hace un backend real cuando habla con otro servicio.

# Buscar en una API real de películas
import requests

resp = requests.get("https://www.omdbapi.com/",
    params={"s": titulo, "apikey": API_KEY})
resp.raise_for_status()
peliculas = resp.json()["Search"]
Módulo 9 · Consumir APIs con requests

Guardar favoritos

Cada usuario marca sus películas y la app las recuerda entre sesiones. Vuelves mañana y siguen ahí. Para que entiendas de verdad cómo persisten los datos — el salto que separa un script de juguete de una app que se puede usar.

Qué aprendes construyéndola

A modelar datos con Flask-SQLAlchemy y a escribir los endpoints que los guardan y los leen: un POST para añadir, un GET para listar. Empiezas guardándolo en una lista en memoria (Módulo 9) y acabas persistiéndolo en base de datos de verdad.

# Marcar una película como vista / favorita
@app.post("/api/usuarios/<int:uid>/vistas")
@jwt_required()
def marcar_vista(uid):
    db.session.add(vista)
    db.session.commit()
    return jsonify(vista), 201
Módulos 8 y 9 · SQLAlchemy + endpoints

Género preferido de cada usuario

Pedro guarda que le va el thriller; Ana, el drama. La app guarda los géneros favoritos de cada uno y los usa para personalizar lo que ve. Para que sepas proteger datos por usuario y entiendas por qué un endpoint sin proteger es un agujero de seguridad.

Qué aprendes construyéndola

A relacionar datos en la base de datos (un usuario, sus géneros) y a proteger esos endpoints con ownership: solo tú puedes cambiar tus propios géneros. Aquí ves de verdad por qué un endpoint sin proteger es un agujero de seguridad.

@app.post("/api/usuarios/<int:uid>/generos-favoritos")
@jwt_required()
def elegir_generos(uid):
    # Solo el propio usuario puede cambiarlos
    if usuario_actual["user_id"] != uid:
        return jsonify(error), 403
Módulos 8 y 9 · Modelos + ownership

Control de usuarios

Registro, login y sesiones con el estándar de la industria. El usuario pedro con el que entraste en la demo es exactamente esto. Para que puedas enseñar en una entrevista que sabes hacer autenticación real, no de tutorial.

Qué aprendes construyéndola

A hacer autenticación de verdad con JWT, el estándar de la industria: hashear contraseñas (nunca en texto plano), emitir un token al hacer login y proteger rutas con @jwt_required(). Incluso roles (usuario normal vs. admin).

# Login: contraseña cifrada → token JWT
if check_password_hash(usuario.hash, contrasena):
    token = create_access_token(identity=usuario.id)
    return jsonify(access_token=token), 200
Módulo 9 · Autenticación JWT

Recomendaciones de películas

La app no muestra un catálogo plano: sugiere películas según lo que has visto y los géneros que te gustan. Para que tengas en tu GitHub una feature de personalización que no tiene el 95% de los portfolios de programadores junior.

Qué aprendes construyéndola

A montar un sistema de recomendaciones: cruzar los géneros favoritos del usuario con el catálogo, filtrar y ordenar resultados. Lo trabajas como reto integrador que junta base de datos, usuarios y lógica de negocio: una feature que te pedirían en un trabajo real de backend.

# Sugerencias según tus géneros favoritos
def recomendar(usuario):
    return [p for p in catalogo
            if p.genero in usuario.generos_favoritos
            and p not in usuario.vistas]
Módulo 5 (POO con sets y polimorfismo) · reforzado como reto integrador en el Módulo 10.5

Afinidad entre usuarios

La app compara tus gustos con los de otros usuarios y calcula cuánto coincidís. "Tú y Pedro tenéis un 80% de afinidad": calculado por tu código. Para que en una entrevista puedas explicar cómo funciona un sistema colaborativo, porque es la base de Spotify, Netflix y cualquier app que te recomienda algo.

Qué aprendes construyéndola

A comparar conjuntos de datos entre usuarios (géneros y películas en común) y a convertir eso en una puntuación. Es la base de cualquier sistema "a quién se parece más" que has visto en apps grandes, montado en pequeño y de verdad.

# Afinidad = gustos en común / gustos totales
def afinidad(a, b):
    comunes = set(a.favoritos) & set(b.favoritos)
    total   = set(a.favoritos) | set(b.favoritos)
    return len(comunes) / len(total)
Módulo 5 — Usuario.afinidad() con índice Jaccard (sets)

De cero a una app con tu nombre en un dominio real

Nadie escribe una API con login el primer día. Se llega por capas. Esta es la progresión real: la misma app, creciendo módulo a módulo, hasta lo que acabas de probar en la demo. No hay saltos de fe. Cada versión funciona antes de pasar a la siguiente.

v0.1
Módulos 1–3

Una idea en la terminal

Variables, input(), listas y funciones. La app pide un título y un rating y los gestiona en memoria. Fea, pero ya funciona.

v3.0
Módulos 4–6

Datos que persisten y código serio

Archivos JSON, SQLite, clases y excepciones. Los datos ya no se pierden al cerrar y el código deja de ser un script para ser algo mantenible.

v5.0
Módulo 8

Deja de ser terminal: es una API

Flask, rutas, JSON y Flask-SQLAlchemy. La app se convierte en una API REST con CRUD completo y base de datos. Ya la puede consumir un navegador o un móvil.

v5.5
Módulo 9

Usuarios, búsqueda real y tests

Búsqueda con la API de OMDB, registro y login con JWT, ownership por usuario y tests con pytest. Cada uno tiene sus favoritos y sus géneros, protegidos. Esto ya es la app de la demo.

PROD
Módulo 10

Metida en internet

Git y GitHub, configuración por entorno, Gunicorn + Nginx y SSL en un VPS. Tu app deja tu portátil y vive en un dominio real, accesible 24/7. Justo como movietracker.elpythonista.com.

En una entrevista, abres este enlace y dices una frase.

"Sé Python" no convence a nadie porque todo el mundo lo dice. Lo que convence es abrir un enlace delante del que te entrevista, hacer login en vivo y decir:

"Esta app la he montado yo. Tiene usuarios con login por JWT, búsqueda contra una API externa, base de datos con SQLAlchemy, tests con pytest y está desplegada en un VPS con Nginx y SSL. Aquí está el código en mi GitHub."

No es teoría. Es una URL que ya funciona, un repositorio que se puede leer y un proyecto que demuestra lo que sabes hacer. Sin pedir que te crean. Ya lo han visto.

Un paso: entra al curso y empieza.

Has abierto la demo. Has visto cada pieza y el módulo donde se monta. Solo queda un paso: pulsa el botón, accede hoy y escribe tu primera línea. La app que acabas de usar te espera al otro lado.

147€
Pago único Acceso de por vida Garantía 14 días
Empezar el curso — 147€ pago único

Sin suscripción. Sin cargos ocultos. Acceso de por vida.
Si en 14 días no es lo que esperabas, te devuelvo el dinero sin preguntas.

Construir esta app · 147€ Primero prueba la demo →