davideghz
davideghz

Reputation: 3685

django rest framework - override viewsets.ViewSet#retrieve in order to use 2 parameters for lookup resource

I'd like to use two model's attributes to lookup a Route's record

models.py

class Route(DateTimeModel):
    start_poi = models.ForeignKey(Poi, related_name="start_pois", on_delete=models.CASCADE)
    end_poi = models.ForeignKey(Poi, related_name="end_pois", on_delete=models.CASCADE)
    ...

    def __str__(self):
        return 'From %s to %s' % (self.start_poi.slug, self.end_poi.slug)

views.py

class RouteViewSet(viewsets.ViewSet):
    http_method_names = ['get']

    @staticmethod
    def list(request):
        queryset = ...

        serializer = RouteSerializer(queryset, many=True)
        return Response(serializer.data)

    @staticmethod
    def retrieve(request, from_poi_slug, to_poi_slug):
        queryset = ...

        route = get_object_or_404(queryset, from_poi_slug=from_poi_slug, to_poi_slug=to_poi_slug)
        serializer = RouteSerializer(route)
        return Response(serializer.data)

urls.py

urlpatterns.extend([
    path(rf'{BASE_API_PATH}/routes/(?P<from_poi_slug>[-\w]+)/(?P<to_poi_slug>[-\w]+)', RouteViewSet),
])

I get

Not Found: /api/v1/routes/xyz/abc [29/Apr/2019 10:07:01] "GET /api/v1/routes/molo-santa-maria/kennedy-ne HTTP/1.1" 404 13191

What am I missing? How can I properly override #retrieve and correctly configure urls?

Upvotes: 0

Views: 2094

Answers (1)

JPG
JPG

Reputation: 88569

Since you are only using read operations, you could use ReadOnlyModelViewSet.

#views.py
class RouteViewSet(viewsets.ReadOnlyModelViewSet):
    http_method_names = ['get']

    def list(self, request, *args, **kwargs):
        queryset = ...

        serializer = RouteSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, *args, **kwargs):
        from_poi_slug = kwargs['from_poi_slug']
        to_poi_slug = kwargs['to_poi_slug']
        queryset = ...

        route = get_object_or_404(queryset, from_poi_slug=from_poi_slug, to_poi_slug=to_poi_slug)
        serializer = RouteSerializer(route)
        return Response(serializer.data)

and in your urls.py

urlpatterns.extend([
    path(rf'{BASE_API_PATH}/routes/(<from_poi_slug>)/(<to_poi_slug>)/', RouteViewSet.as_view({"get": "retrieve"})),
])

Upvotes: 2

Related Questions