Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering Django ModelViewSet List From Url Parameter

Hi I have a model like:

class Appointment(models.Model):
    hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE)
    patient = models.ForeignKey(Patient, on_delete=models.CASCADE)

My View looks like:

class AppointmentViewSet(viewsets.ModelViewSet):
    queryset = Appointment.objects.all()
    serializer_class = AppointmentSerializer

In my urls:

router.register(r'appointments', AppointmentViewSet)

Now I want to filter the list of appointments by some patient id. This id should be given by the requester through url. I'm thinking about using kwargs to catch it. But I have no idea how to do it. I know I have to override the list method.

def list(self, request, *args, **kwargs):
    # what do I write here? so that the queryset would be filtered by patient id sent through the url? 

How do I customize the url and/or the view to accommodate the patient id parameter? I just want to modify the list request, all other actions(create, details, destroy) should be handled by the modelviewset's default behavior.

Thanks.

like image 795
QuestionEverything Avatar asked Jun 14 '17 04:06

QuestionEverything


2 Answers

Here is how I ended up doing it:

I've added an url entry like this:

url(r'appointments/ofpatient/(?P<patient>\d+)', AppointmentViewSet.as_view({'get': 'list'})),

Which I can call from the browser as:

http://localhost:8000/appointments/ofpatient/6

and in view:

def list(self, request, patient=None):
    if patient:
        patient = Patient.active.filter(id=patient)
        appts = Appointment.active.order_by('appt_time').filter(patient=patient)
        serializer = self.get_serializer(appts, many=True)
        return Response(serializer.data)
    else:
        appts = Appointment.active.order_by('appt_time')
        serializer = self.get_serializer(appts, many=True)
        return Response(serializer.data)

In this way, the /appointments url is also preserved.

like image 50
QuestionEverything Avatar answered Nov 10 '22 07:11

QuestionEverything


You can define a custom method to handle the routing for the url with the patient id:

from rest_framework.decorators import list_route
rom rest_framework.response import Response

class AppointmentViewSet(viewsets.ModelViewSet):
    ...

    @list_route()
    def patient_appointments(self, request, id=None):
        serializer = self.get_serializer(queryset.filter(patient_id=id), many=True)
        return Response(serializer.data)

The list_route decorator marks your method as requiring routing.

Update:

You can manually register the url as:

url(r'^(?P<id>[0-9]+)/appointments/$', AppointmentViewSet.as_view({'get': 'patient_appointments'}), name='patient-appointments')
like image 30
Moses Koledoye Avatar answered Nov 10 '22 07:11

Moses Koledoye