73

I am trying to return custom json with get_queryset but always get 404 error in response.

class TestViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Test.objects.all()
    serializer_class = TestSerializer

    def get_queryset(self):
        if self.request.method == "GET":
            content = {'user_count': '2'}
            return HttpResponse(json.dumps(content), content_type='application/json')

If I delete everything starting from def I'll got correct response with standard json data. What I am doing wrong?

bakkal
  • 54,350
  • 12
  • 131
  • 107
Roberto
  • 1,472
  • 2
  • 16
  • 18
  • I've never used DRF, but by looking at the function name shouldn't `get_queryset` return a queryset? – Shang Wang Jan 26 '16 at 16:41
  • 1
    @ShangWang in that case what method is better to use to handle get request and to response with custom json? – Roberto Jan 26 '16 at 16:43

2 Answers2

102

If you don't need a ModelViewSet and just want custom JSON on a GET request

You can also use an APIView, which doesn't require a model

class MyOwnView(APIView):
    def get(self, request):
        return Response({'some': 'data'})

and

urlpatterns = [
    url(r'^my-own-view/$', MyOwnView.as_view()),
]

With a ModelViewSet

You've put the custom JSON into get_queryset, that's wrong. If you want to use a ModelViewSet, this by itself should be enough:

class TestViewSet(viewsets.ModelViewSet):
    queryset = Test.objects.all()
    serializer_class = TestSerializer

This ModelViewSet comes with default implementations for .list(), .retrieve(), .create(), .update(), and .destroy(). Which are available for you to override (customize) as needed

Returning custom JSON from .retrieve() and/or .list() in ModelViewSet

E.g. to override .retrieve() to return custom view when retrieving a single object. We can have a look at the default implementation which looks like this:

def retrieve(self, request, *args, **kwargs):
    instance = self.get_object()
    serializer = self.get_serializer(instance)
    return Response(serializer.data)

So as an example to return custom JSON:

class TestViewSet(viewsets.ModelViewSet):
    queryset = Test.objects.all()
    serializer_class = TestSerializer

    def retrieve(self, request, *args, **kwargs):
        return Response({'something': 'my custom JSON'})

    def list(self, request, *args, **kwargs):
        return Response({'something': 'my custom JSON'})
chris Frisina
  • 19,086
  • 22
  • 87
  • 167
bakkal
  • 54,350
  • 12
  • 131
  • 107
  • 2
    @VaggelisManousakis The same job in different scenarios: if all I am doing is returning custom data, I would go with the direct route of the `APIView`. If I'm using a `ModelViewSet` and need some custom data, I would override the methods that I need. – bakkal Oct 09 '18 at 09:15
  • 1
    you should now use JsonResponse() instead of Response() to return custom json from an APIView – Mar Oct 15 '21 at 07:45
10

There are 2 ways to custom the response in Class-based views with ModelViewSet

Solution 1: custom in views.py

class StoryViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.AllowAny,)
    queryset = Story.objects.all()
    serializer_class = StorySerializer

    def retrieve(self, request, *args, **kwargs):
        # ret = super(StoryViewSet, self).retrieve(request)
        return Response({'key': 'single value'})

    def list(self, request, *args, **kwargs):
        # ret = super(StoryViewSet, self).list(request)
        return Response({'key': 'list value'})

Solution 2: custom in serializers.py (I recommend this solution)

class StorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Story
        fields = "__all__"

    def to_representation(self, instance):
        ret = super(StorySerializer, self).to_representation(instance)
        # check the request is list view or detail view
        is_list_view = isinstance(self.instance, list)
        extra_ret = {'key': 'list value'} if is_list_view else {'key': 'single value'}
        ret.update(extra_ret)
        return ret
HoangYell
  • 4,100
  • 37
  • 31
  • 1
    woudl you mind taking a look at this quest from me! https://stackoverflow.com/questions/56978902/how-to-override-returned-serializer-object-that-is-returned-with-the-response-dj – Omar Jandali Jul 10 '19 at 21:37