Django select_related() vs prefetch_related(): SQL generado

Django select_related() vs prefetch_related(): SQL generado

¿select_related() o prefetch_related()? Ambos métodos eliminan consultas N+1 en Django, pero no generan en absoluto el mismo SQL. El primero añade un join a la consulta principal. El segundo ejecuta varias consultas y después relaciona los objetos en Python. La elección correcta depende menos del volumen de datos que del tipo de relación recorrida. Para entenderlo, partamos de un modelo deliberadamente sencillo: from django.conf import settings from django.db import models class Post(models.Model): title = models.CharField(max_length=200) author = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="posts", ) tags = models.ManyToManyField("Tag", related_name="posts") class Comment(models.Model): post = models.ForeignKey( Post, on_delete=models.CASCADE, related_name="comments", ) body = models.TextField() is_public = models.BooleanField(default=True) author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) class Tag(models.Model): name = models.CharField(max_length=50) Desde un Post, author designa como máximo a un usuario. En cambio, comments y tags pueden contener varios objetos. Esta diferencia de cardinalidad dicta casi siempre qué método utilizar. ...

20 de julio de 2026 · 8 min · Anthony
GitOps sin Kubernetes: Django con doco-cd, SOPS y age

GitOps sin Kubernetes: Django con doco-cd, SOPS y age

GitOps casi siempre se presenta con Kubernetes de fondo: ArgoCD, Flux, manifests por centenares. El resultado es que muchos equipos que despliegan en un simple VPS con Docker Compose asumen que el modelo no va con ellos. Siguen desplegando por SSH: git pull, docker compose up -d, cruzando los dedos para que nadie se salte un paso. Es una lástima, porque el núcleo de GitOps no tiene nada que ver con Kubernetes. Y desde hace un tiempo existe una herramienta que cubre exactamente ese hueco: doco-cd, un motor de despliegue continuo para Docker Compose. Combinado con SOPS y age para cifrar los secretos directamente en el repo, se obtiene GitOps sin Kubernetes: un pipeline completo donde desplegar se reduce a un git push. Este artículo explica el principio y luego recorre la puesta en marcha en un proyecto Django con varios ficheros compose. ...

29 de junio de 2026 · 10 min · Anthony
CQRS en Django: un read model desnormalizado sin Event Sourcing

CQRS en Django: un read model desnormalizado sin Event Sourcing

Los cuatro artículos anteriores de la serie pusieron las bases para que un sistema distribuido se mantenga coherente: Saga para orquestar workflows, Outbox para publicar eventos fiables, Inbox para consumirlos sin duplicados, Idempotency Keys para proteger la API. Queda una pregunta: ¿qué se hace con los eventos una vez publicados? La respuesta más frecuente es: se usan para construir vistas de lectura. Es exactamente lo que propone el patrón CQRS (Command Query Responsibility Segregation): separar el modelo de escritura del modelo de lectura, cuando ambos divergen lo suficiente como para que forzarlos en una misma estructura cueste más que duplicarlos. ...

5 de junio de 2026 · 8 min · Anthony
Idempotency Keys: evitar que un cliente pague dos veces

Idempotency Keys: evitar que un cliente pague dos veces

Los dos artículos anteriores trataron la idempotencia del lado evento: el patrón Outbox garantiza que un mensaje se publica al menos una vez, y el patrón Inbox garantiza que solo se consume una vez. Queda un tercer lugar donde aparece el mismo problema, más arriba: la propia API HTTP. Cuando un cliente lanza un POST /api/payments y su conexión se cae antes de recibir la respuesta, no sabe si el pago se creó o no. Si reintenta, arriesga pagar dos veces. Si no reintenta, arriesga no pagar nada. El patrón Idempotency Key, popularizado por Stripe y adoptado desde por la mayoría de APIs de pago, resuelve ese dilema poniendo el control del retry en manos del cliente. ...

4 de junio de 2026 · 8 min · Anthony
Patrón Inbox: consumir eventos sin reproducirlos dos veces

Patrón Inbox: consumir eventos sin reproducirlos dos veces

El artículo anterior sobre el Transactional Outbox estableció una garantía clara: todo evento escrito en base acabará siendo publicado. Esa garantía es intencionadamente at-least-once. Un consumidor puede recibir el mismo evento dos veces, tres veces, o más si la red se porta mal. El patrón Outbox nunca promete unicidad. La consecuencia es inmediata: si el consumidor aplica dos veces el efecto del mensaje, factura dos veces, envía dos correos, descuenta stock dos veces. La coherencia garantizada del lado productor se rompe del lado lector. ...

3 de junio de 2026 · 7 min · Anthony
Transactional Outbox: publicar eventos sin perder la coherencia

Transactional Outbox: publicar eventos sin perder la coherencia

Cuando un servicio modifica su base y quiere avisar al resto del sistema enviando un evento a Kafka, RabbitMQ o SQS, el código ingenuo se parece a esto: escribir en base y luego publicar. Si la publicación falla tras el commit, el evento se pierde. Si la publicación tiene éxito pero el commit falla, el evento habla de un estado que no existe. Ambos casos son la definición del dual-write problem. ...

2 de junio de 2026 · 8 min · Anthony
Patrón Saga: gestionar transacciones distribuidas sin rollback

Patrón Saga: gestionar transacciones distribuidas sin rollback

Una operación de negocio que toca varios servicios plantea una pregunta que SQL resuelve desde hace cincuenta años dentro de una sola base de datos: ¿qué pasa cuando un paso tiene éxito y el siguiente falla? Mientras todo vive en la misma base, BEGIN ... ROLLBACK basta. En cuanto llamas a un servicio externo, una API de terceros u otra base de datos, esa red de seguridad desaparece. El patrón Saga responde a esa pregunta. En lugar de intentar una transacción ACID imposible, divide la operación en pasos locales, cada uno acompañado de una transacción compensatoria que sabe deshacer su efecto. Si el paso 4 falla, las compensaciones de los pasos 1, 2 y 3 se reproducen en orden inverso. ...

1 de junio de 2026 · 8 min · Anthony
Permisos declarativos en DRF con rest_access_policy

Permisos declarativos en DRF con rest_access_policy

Los permisos en Django REST Framework funcionan, pero muestran sus límites en cuanto las reglas de acceso se vuelven moderadamente complejas. Varios roles, objetos pertenecientes a un usuario específico, acciones custom en un ViewSet: acabas con clases has_permission y has_object_permission que mezclan verificaciones heterogéneas, difíciles de leer y aún más difíciles de testear. rest_access_policy (paquete djangorestframework-access-policy) propone un enfoque diferente: declarar las reglas de acceso como statements, similar a las políticas IAM de AWS. El resultado es legible de un vistazo, testeable independientemente del ViewSet, y extensible sin reescribir toda la clase. ...

26 de mayo de 2026 · 7 min · Anthony
Hash, HMAC y cifrado: cómo proteger un token en Django

Hash, HMAC y cifrado: cómo proteger un token en Django

Una comparación == sobre un hash no es suficiente para elegir el mecanismo correcto. sha256, HMAC, hash salado, cifrado: cada enfoque ofrece garantías distintas. Entender cuáles son cambia concretamente la forma de almacenar y verificar un token en Django. Hash simple import hashlib token_hash = hashlib.sha256(token.encode()).hexdigest() Un hash simple es determinista: la misma entrada siempre produce la misma salida. No interviene ningún secreto del servidor. Es imposible recuperar el token original a partir del hash (sha256 es una función unidireccional). Pero si alguien conoce o adivina el token, puede recalcular el hash y comparar. ...

25 de mayo de 2026 · 4 min · Anthony
Django: save() no llama a full_clean() — ciclo de validación

Django: save() no llama a full_clean() — ciclo de validación

Llamar a obj.save() después de definir validators y un método clean() en el modelo da la impresión de que la validación está garantizada. No lo está. Django no llama a full_clean() durante un save(), y este comportamiento es deliberado. Entender por qué cambia la forma de diseñar la validación en un proyecto. Lo que save() hace realmente El ciclo de vida de un save() es más corto de lo que parece: ...

18 de mayo de 2026 · 5 min · Anthony

Newsletter

Recibe los nuevos artículos directamente en tu bandeja de entrada.

Sin spam. Baja en un clic.