D/ DJANGO CON CRITERIO

UNIDAD 2 · APIS Y CASOS DE USO

CQS: consultar y ejecutar

Separa Queries y Commands sin añadir infraestructura innecesaria.

Ilustración: Dos carriles para dos intenciones
Dos carriles para dos intenciones

ISLA DJANGO · MUNDO 01

Aprende CQS jugando.

Acompaña a Byte por cinco estaciones y decide qué debe hacer cada petición.

Abrir aventura a pantalla completa ↗

Tres misiones: consultar, crear y rechazar una entrada inválida. Se puede jugar con ratón, controles táctiles o teclado.

CAPÍTULO 3 · Cada pieza encuentra su responsabilidad

Separar las preguntas de los cambios

Al incorporar más operaciones, views.py puede convertirse en el lugar donde todo sucede. Buscar un sensor queda junto a crearlo, editarlo y resolver reglas que no pertenecen al transporte HTTP. Localizar una función resulta cada vez más costoso porque el archivo reúne intenciones diferentes, aunque todas reciban una petición.

En una experiencia previa con Clean Architecture, un desarrollador senior me ayudó a valorar la responsabilidad de cada pieza. Esa enseñanza conecta aquí con CQS: una consulta responde una pregunta y un comando expresa una intención de cambio. Organizamos queries y commands para que el nombre y la ubicación nos permitan anticipar qué debería hacer el código.

La petición sigue entrando por las URLs principales. include delega una parte de la ruta a las URLs de la app y estas seleccionan la clase correspondiente; es resolución interna, no una redirección del navegador. La separación facilita leer y probar, pero no elimina por sí sola los errores compartidos. Además deja visible otra pregunta: si la misma regla debe ejecutarse desde una tarea, ¿tendrá que pasar también por una vista?

Leer esta parte dentro del relato completo →

DEL RELATO A LA PRÁCTICA

Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.

MIRA · CONECTA · COMPRENDE

Dos carriles para dos intenciones

Dos carriles para dos intenciones1. Petición: Expresa una intención; 2. Query: Consulta sin cambiar estado; 3. Command: Ejecuta una operación; 4. Estado: Se consulta o modifica según carril01PeticiónExpresa una intención02QueryConsulta sin cambiar estado03CommandEjecuta una operación04EstadoSe consulta o modifica segúncarril

La intención separa consulta y comando. El comando cambia estado; la consulta lo lee.

Selecciona una pieza para destacar su responsabilidad.

Leer la explicación del mapa
  1. Petición. Expresa una intención
  2. Query. Consulta sin cambiar estado
  3. Command. Ejecuta una operación
  4. Estado. Se consulta o modifica según carril
Descargar gráfico SVG ↓

¿Para qué sirve?

Una consulta que modifica datos sorprende al cliente y hace peligrosas las repeticiones. CQS mantiene clara la intención de cada operación.

El concepto, explicado

Una Query responde una pregunta sin modificar estado de negocio. Un Command ejecuta una intención que normalmente cambia estado. Pueden compartir modelos y base de datos.

CQRS agrega separación de modelos de lectura y escritura cuando lo necesitas. Crear carpetas Commands y Queries no implica buses, eventos o almacenes independientes.

En un proyecto anterior con Clean Architecture, un desarrollador senior ayudó al autor a valorar la responsabilidad de cada pieza. CQS conecta esa enseñanza con la separación entre consultas y comandos. Se relaciona con responsabilidad única, pero no equivale a todos los principios SOLID ni garantiza aislamiento de fallos: un error de importación aún puede impedir el arranque.

config/urls.py reconoce el prefijo y include delega el resto de la ruta a las URLs de la app. Allí path selecciona la vista y as_view() crea el callable para una clase. Es resolución interna; no una redirección HTTP al navegador. El middleware puede actuar antes y después de la vista.

Implementación paso a paso

  1. Crea ListSensorQuery para GET.
  2. Crea CreateSensorCommand para POST.
  3. Coloca algoritmos complejos en servicios.
  4. Define contratos de respuesta y repetición.

Ejemplo en SensorHub

# catalogo/views/commands.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from catalogo.serializers import SensorSerializer

class CreateSensorCommand(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        serializer = SensorSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sensor = serializer.save()
        return Response({"success": True, "id": str(sensor.id)}, status=201)

Cómo leer el ejemplo

  • El ejemplo pertenece a SensorHub, que puede requerir identidad; no activa login en la academia.
  • La vista valida entrada y persiste una intención concreta.
  • Un GET nunca debería registrar sensores ni disparar una detección persistente.

Error habitual

IsAuthenticated no verifica capacidad de crear sensores. Más adelante agregaremos autorización por capacidad.

05 / PRACTICAR

Tu turno

Diseña una Query que retorne sensores activos.

Ver solución orientativa

Usa Sensor.objects.filter(active=True), serializer many=True y método GET sin save ni update.

Cómo sabes que funciona

  • GET repetido no cambia el número de sensores.
  • POST válido responde 201 y crea uno.

Para profundizar

Documentación oficial para comprobar configuración, permisos y condiciones vigentes. Revisión del tema: .

CONTINUAR LA EXPERIENCIA

El siguiente paso del recorrido:

Servicios y casos de uso →Continuar en modo relato