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
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
- Petición. Expresa una intención
- Query. Consulta sin cambiar estado
- Command. Ejecuta una operación
- Estado. Se consulta o modifica según carril
01 / EL PROBLEMA
¿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.
02 / COMPRENDER
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.
03 / CONSTRUIR
Implementación paso a paso
- Crea ListSensorQuery para GET.
- Crea CreateSensorCommand para POST.
- Coloca algoritmos complejos en servicios.
- Define contratos de respuesta y repetición.
04 / APLICAR
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.
06 / VERIFICAR
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