Optimiza tu API con confianza: las vistas genéricas de Django Rest permiten crear una vista de detalle que obtiene, actualiza y elimina un recurso, reduciendo código y errores. Aquí verás cómo pasar de lógica duplicada a una implementación clara y reutilizable.
¿Por qué usar vistas genéricas para el detalle?
Las vistas genéricas permiten obtener el objeto, modificarlo, borrarlo o mostrarlo como JSON sin escribir lógica repetida. En lugar de manejar manualmente el 404 por ID y repetir consultas, se hereda de una clase que ya incluye estas operaciones.
Menos código y menos duplicación.
Manejo automático de error 404 cuando el ID no existe.
Soporte integrado para métodos como GET, PUT y DELETE.
¿Cómo evitar código duplicado con vistas genéricas?
La clave es reemplazar el uso de ApiView por una clase que combine operaciones. En lugar de importar y usar por separado RetrieveApiView, UpdateApiView y DestroyApiView, se utiliza una sola clase que reúne todo: la combinada de retrieve, update y destroy.
# Vista de detalle simplificada (esqueleto)classPacienteDetailView(RetrieveUpdateDestroyApiView): queryset =...# colección de pacientes. serializer_class =...# serializador del paciente.# Ya no se implementa get_object ni el 404 manual.
El resultado: el código “sigue funcionando perfectamente” y se eliminan bloques redundantes.
¿Qué diferencia hay entre las clases individuales y la combinada?
RetrieveApiView: obtiene un recurso.
UpdateApiView: actualiza un recurso.
DestroyApiView: elimina un recurso.
Combinada retrieve, update y destroy: incluye las tres funcionalidades en una sola vista. Si solo quieres permitir actualizaciones, importa únicamente la de update; si quieres todo, usa la combinada.
¿Qué variables hay que definir al heredar de la clase combinada?
Basta con “volver a definir estas mismas variables” ya usadas en la vista previa, típicamente las que indican la colección de objetos y el serializador. Con eso, no hace falta el código manual para buscar por ID ni devolver 404.
¿Cómo validar desde el navegador que todo funciona?
La verificación es directa: se accede al detalle de un paciente (por ejemplo, el ID 3) y funciona. Aparecen un botón de Delete y un formulario que permite editar; incluso es posible enviar cambios con raw data.
¿Cómo probar GET, PUT y delete desde el detalle?
GET por ID: obtener el recurso “tres” y ver su detalle.
PUT para actualizar: cambiar, por ejemplo, el correo a “Platzi” y recibir 200 con el nuevo valor reflejado.
DELETE: disponible con el botón del detalle.
¿Qué aportan los mensajes de error al front end?
Si envías un dato inválido (por ejemplo, una “fecha de nacimiento” no válida), al guardar se muestran mensajes de error claros. Esto es muy útil para el front end: explica por qué el request falla y qué campo corregir.
¿Qué mejoras aporta el formulario y el raw data?
Edición directa en el formulario del detalle.
Envío de cambios con raw data sin copiar y pegar.
Flujo más rápido para iterar sobre pruebas y validaciones.
¿Qué sigue: view sets y nuevos endpoints?
El siguiente paso es usar view sets para agrupar vistas sin repetirse, incluso cuando aún queden “dos líneas” duplicadas. Con el endpoint de pacientes ya listo usando vistas basadas en clases (tras el refactor desde vistas basadas en funciones), llega el momento de crear los endpoints de doctores y citas. Todo el código, muy parecido entre sí, estará disponible en el repositorio de recursos.
¿Por qué usar view sets para agrupar vistas?
Reducen repetición en configuraciones comunes.
Centralizan operaciones de lista, detalle, actualización y borrado.
Preparan la base para trabajar con varios endpoints sin reescribir lógica.
¿Te quedaron dudas sobre la migración a vistas genéricas o view sets? Comenta qué parte de tu API quieres simplificar y qué operaciones necesitas incluir.
Casa abstracciones que trae son muy útiles, es importante conocer cómo funciona para hacer ajustes en momentos que lo requieras
Si por alguna razon les nace ocupar la palabra id en la url en lugar de pk que tenes que saber que se puede. el profe por defecto ocupa pk como convencion de Django, pero se puede cambiar asi
Sinceramente muy impresionado con la simplificación que tiene django :)
Es muy útil cuando estás escribiendo varios en Points y básicamente sólo debes copiar y pegar y cambiar el nombre del modelo
Como tip: cuando empezamos a usar vistas genericas ya no es necesario declarar los metodos: ["GET", "PUT", "DELETE"]) vienen implicitos.
Hermoso código:
from.serializers import PatientSerializer
from.models import Patient
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.generics import( ListAPIView, CreateAPIView, RetrieveUpdateDestroyAPIView,)# GET /api/patients => Listar# POST /api/patients => Crear# GET /api/patients/<pk>/ => Detalle# PUT /api/patients/<pk>/ => Modificación# DELETE /api/patients/<pk>/ => BorrarclassListPatientsView(ListAPIView, CreateAPIView): allowed_methods =['GET','POST'] serializer_class = PatientSerializer
queryset = Patient.objects.all()classDetailPatientView(RetrieveUpdateDestroyAPIView): allowed_methods =['GET','PUT','DELETE'] serializer_class = PatientSerializer
queryset = Patient.objects.all()
Django REST Framework es una maravilla, te ahorra muchas cosas
Ventajas de utilizar vistas genéricas en Django Rest Framework:
Reducción de código repetitivo: Implementaciones predefinidas para operaciones comunes.
Mejora de consistencia y mantenibilidad: Aplicación de patrones uniformes en toda la API.
Aceleración del desarrollo: Permite centrarse en la lógica específica de la aplicación.
Facilidad de integración y extensión: Composición de comportamientos reutilizables.
Promoción de buenas prácticas: Adherencia a los principios de diseño de Django y REST.
classPatientRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):"""
API endpoint that allows a patient to be retrieved, updated or deleted.GET:Returns a single patient by IDPUT:Updates an existing patient
PATCH:Partially updates an existing patient
DELETE:Deletes a patient
"""
queryset =Patient.objects.all() serializer_class =PatientSerializer lookup_field ="pk"
Vaya , Yo debo decir que el grado de abstracción en vistas pre-fabricadas "genericas" en DRF es tan talto nivel que ya comienzo a sentirme incomodo "Vago" por solo extender y herdear vistas que ya estan hechas en el framwork por alguien mas de la comunidad. el codigo actual ha sido REFACTOR tantas veces que ya ni se parece al original de Vistas basadas en Funciones.
Yo realmente aprecio la intencion del profesor de mostrar como se hacen esos metodos de vistas uno a uno usando HTTP Methods , eso explica de donde provienen las funciones que ya estan tan abstraidas a un nivel superiro que ni parecen su verdadera codigo .
El Curso esta Genial. El Profe @Luis Explcia Bien como sieMpre.
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from.models import Cliente, Reserva, Historial
from.serializers import ClienteSerializer, ReservaSerializer, HistorialSerializer
classClienteViewSet(viewsets.ModelViewSet): queryset = Cliente.objects.all() serializer_class = ClienteSerializer
defretrieve(self, request, pk=None):"""
Sobrescribe el método retrieve para personalizar la respuesta al obtener un cliente por su pk.
"""try: cliente = Cliente.objects.get(pk=pk) serializer = ClienteSerializer(cliente)return Response(serializer.data, status=status.HTTP_200_OK)except Cliente.DoesNotExist:return Response({"error":"Cliente no encontrado"}, status=status.HTTP_404_NOT_FOUND)classReservaViewSet(viewsets.ModelViewSet): queryset = Reserva.objects.all() serializer_class = ReservaSerializer
classHistorialViewSet(viewsets.ModelViewSet): queryset = Historial.objects.all() serializer_class = HistorialSerializer
```from rest\_framework import viewsetsfrom rest\_framework.response import Responsefrom rest\_framework import statusfrom .models import Cliente, Reserva, Historialfrom .serializers import ClienteSerializer, ReservaSerializer, HistorialSerializer
classClienteViewSet(viewsets.ModelViewSet): queryset = Cliente.objects.all() serializer\_class = ClienteSerializer
defretrieve(self, request, pk=None):""" Sobrescribe el método retrieve para personalizar la respuesta al obtener un cliente por su pk. """try: cliente = Cliente.objects.get(pk=pk) serializer = ClienteSerializer(cliente)return Response(serializer.data, status=status.HTTP\_200\_OK)except Cliente.DoesNotExist:return Response({"error":"Cliente no encontrado"}, status=status.HTTP\_404\_NOT\_FOUND)classReservaViewSet(viewsets.ModelViewSet): queryset = Reserva.objects.all() serializer\_class = ReservaSerializer
classHistorialViewSet(viewsets.ModelViewSet): queryset = Historial.objects.all() serializer\_class = HistorialSerializer