0

I am trying to set up an API endpoint that returns a singular object.

Right now I have:

class ShoppingCartViewSet(viewsets.GenericViewSet, mixins.ListModelMixin):
    """
    API endpoint that allows users to be viewed or edited.
    """
    serializer_class = ShoppingCartSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get_paginated_response(self, data):
        return Response(data)

    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)

Which uses the ListModelMixin and a filter to return one item, becasue each user has 1 shopping cart.

The issue is the filter function returns a queryset, but I only want a single item.

I attempted to use the RetrieveModelMixin but that doesn't run on the endpoint that I want. Retrieve runs on .../api/shopping-cart/id but I want to retrieve on .../api/shopping-cart because the filtering is done via the person who is logged in.

Any solutions?

Kenny Ye
  • 587
  • 1
  • 5
  • 12

3 Answers3

0

I'm not sure if you have tried this but it should be worthwhile (although I'm not sure if it'll work)

def get_queryset(self):
    return ShoppingCart.objects.filter(user=self.request.user)[:1]
Higor Rossato
  • 1,996
  • 1
  • 10
  • 15
0

Why not use simple api view instead of viewset class?

from django.http import Http404
from rest_framework import status, views

class ShoppingCartAPIView(views.APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get_object(self):
        # use .get if you are really sure it can only be one shopping cart per user
        try:
            return ShoppingCart.objects.get(user=self.request.user)
        except ShoppingCart.DoesNotExist:
            raise Http404()

    def get(self, request):
        obj = self.get_object()        
        data = ShoppingCartSerializer().to_representation(obj)
        return Response(data, status=status.HTTP_200_OK)

You can even create logic for other http methods like post, delete.

Then add the url pattern api/shopping-cart as normal url (in urls.py), not router ones.

Gabriel Muj
  • 3,682
  • 1
  • 19
  • 28
0

The way I ended up solving it was still using the ListModelMixin, as I needed to benefits of the viewset.

I overwrote the list() method with:

class ShoppingCartViewSet(viewsets.GenericViewSet, mixins.ListModelMixin):
    """
    API endpoint that allows users to be viewed or edited.
    """
    serializer_class = ShoppingCartSerializer
    # authentication_classes = (TokenAuthentication,)
    # permission_classes = (IsAuthenticated,)

    def get_paginated_response(self, data):
        return Response(data)

    def list(self, request, *args, **kwargs):
        instance = ShoppingCart.objects.get(user=self.request.user)
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

which returns me a singular item on the root url .../api/shopping-cart without having to pass parameters because it filters based on user.

Kenny Ye
  • 587
  • 1
  • 5
  • 12