Resumen

Agendar citas en una API médica requiere precisión. Aquí verás cómo construir un endpoint anidado en Django Rest para crear y listar appointments desde el viewset de doctores, aplicando validación con serializer, filtros con el ORM y respuestas HTTP claras. La solución es segura, reusable y alineada con REST.

¿Cómo estructurar el endpoint anidado para appointments?

Un endpoint anidado aprovecha el recurso padre. En este caso, se cuelga de Doctors: el camino queda como /doctors/{id}/appointments/. Para lograrlo, se define una @action en el viewset del doctor con detail=True y métodos get y post. Además, se especifica serializer_class para mostrar los campos correctos en la interfaz navegable de Django Rest.

  • detail=True limita la acción al recurso doctor actual.
  • serializer_class evita que se muestren campos del doctor cuando se crea un appointment.
  • get debe listar appointments del doctor. post debe crearlos.
from rest_framework.decorators import action
from rest_framework import status, viewsets
from rest_framework.response import Response
from bookings.serializers import AppointmentSerializer
from bookings.models import Appointment

class DoctorViewSet(viewsets.ModelViewSet):
    ...
    @action(detail=True, methods=['get', 'post'], serializer_class=AppointmentSerializer)
    def appointments(self, request, pk=None):
        doctor = self.get_object()
        if request.method.lower() == 'post':
            data = {**request.data, 'doctor': doctor.id}
            serializer = AppointmentSerializer(data=data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        appointments = Appointment.objects.filter(doctor=doctor)
        serializer = AppointmentSerializer(appointments, many=True)
        return Response(serializer.data)

¿Cómo crear una cita con post usando serializer y validación?

El objetivo es que el usuario no pueda manipular el doctor. Por eso, se inyecta el id del doctor desde la URL con self.get_object() y se construye un diccionario data que combina los datos del usuario con el doctor.id. Luego se instancia el serializer con data, se valida y se guarda.

  • self.get_object() obtiene el doctor según el pk de la URL.
  • request.method dirige el flujo entre post y get.
  • serializer.is_valid(raise_exception=True) aplica reglas de validación y devuelve errores claros.
  • serializer.save() persiste el appointment porque es un ModelSerializer.
  • Response(..., status=status.HTTP_201_CREATED) confirma creación.
doctor = self.get_object()
if request.method.lower() == 'post':
    data = {**request.data, 'doctor': doctor.id}
    serializer = AppointmentSerializer(data=data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data, status=status.HTTP_201_CREATED)

Habilidades y conceptos en juego: - Seguridad por diseño: el doctor se toma de la URL, no del cuerpo del request. - Buenas prácticas REST: post crea, get lista. - Experiencia de desarrollo: el serializer_class en el decorador muestra el formulario correcto en la interfaz navegable. - Control de acceso: el endpoint requiere estar logueado.

¿Cómo listar las citas con get filtrando por doctor?

Para listar, se filtran los appointments por el doctor actual con el ORM de Django y se serializan con many=True. El estado por defecto es 200, por lo que no es necesario especificarlo.

  • Appointment.objects.filter(doctor=doctor) devuelve solo las citas del doctor.
  • many=True indica que se serializa una colección.
  • Response(serializer.data) retorna JSON listo para el cliente.
appointments = Appointment.objects.filter(doctor=doctor)
serializer = AppointmentSerializer(appointments, many=True)
return Response(serializer.data)

Keywords y datos importantes para fijar aprendizaje: - url del recurso: /doctors/{id}/appointments/. - acción anidada con @action(detail=True, methods=['get', 'post']). - uso de serializer_class=AppointmentSerializer en el decorador. - patrón de validación: is_valid(raise_exception=True). - creación con save() y confirmación HTTP_201_CREATED. - listado con many=True y ORM filtrando por doctor=doctor. - vista de detalle: la acción depende del doctor existente. - interfaz navegable: sin serializer_class se mostrarían campos del doctor por defecto. - control de sesión: acceso solo para usuarios autenticados. - acciones extra: ejemplo previo set_on_vacation en Doctors.

¿Tienes dudas o quieres extenderlo con borrar una cita en la misma acción? comenta cómo planeas manejar permisos y validaciones, y lo revisamos juntos.