Módulo 2 · Bases de datos

Lección 11 — Migraciones versionadas

Cambios de esquema sin caída: cómo evolucionar TicketFlow con datos reales dentro.

Publicada
En esta lección
  1. Ejercicio 1 — El renombrado sin caída
  2. Ejercicio 2 — El NOT NULL peligroso, hecho seguro
  3. Ejercicio 3 — Índice CONCURRENTLY
  4. Ejercicio 4 — Las 3 mejoras de la 08
  5. Entrega

En una rama nueva (feat/migraciones-seguras) con copia de tu BD. No mires solutions.md hasta entregar.

Ejercicio 1 — El renombrado sin caída

Modelo: tu evento tiene title (si ya se llama así, crea un campo gemelo temporal para el ejercicio).

  1. Añade label = CharField(null=True) (EXPAND) y migra.
  2. Escribe la migración de datos que copia title → label por lotes (pk paginado), con reverse noop.
  3. Cambia el código para escribir/leer label (dual write: guarda en ambos). Demuestra con shell que ambas columnas quedan iguales tras crear 3 eventos.
  4. Simula el SWITCH (el código ya solo usa label) y escribe la migración CONTRACT que elimina title. ¿Qué rompería ejecutar el código viejo justo después de este paso?

Ejercicio 2 — El NOT NULL peligroso, hecho seguro

  1. Intenta AddField(field=CharField(max_length=16, null=False, default="")) sobre una tabla con filas: ¿qué genera Django y qué hace PostgreSQL?
  2. Hazlo por el camino largo: añadir nullable → backfill con RunPython por lotes → AlterField a NOT NULL. Verifica el tiempo de cada paso con EXPLAIN-mental (o \timing en los pasos SQL).
  3. Instala django-migration-linter y corre el lint sobre tu app: ¿marca operaciones peligrosas de tu historial?

Ejercicio 3 — Índice CONCURRENTLY

  1. En una migración con atomic = False, crea con RunSQL un índice CONCURRENTLY sobre una columna consultada (p. ej. reservation.created_at).
  2. Intenta lo mismo sin CONCURRENTLY en una tabla grande (o simula con 100k filas): ¿bloquea escrituras mientras corre? ¿Qué pasa si falla a medias el CONCURRENTLY (índice INVALID)?
  3. Escribe el check para detectar índices INVALID: SELECT * FROM pg_index WHERE NOT indisvalid;

Ejercicio 4 — Las 3 mejoras de la 08

Aplica tus mejoras anotadas con migraciones seguras (una por mejora, lint verde):

  1. NOT NULL con backfill donde corresponda.
  2. CHECK de coherencia (expires_at > created_at en reservation) — ¿qué pasa con filas viejas que lo violan? (backfill/corrección primero).
  3. slug único en evento con generación para el histórico.

Entrega

Pega migraciones y outputs. Cierra la 11; después Lección 12 — NoSQL.