3

I have a model Foo which I use as the model for my vanilla DRF serializer.

models.py

class Foo(models.Model):
    name = models.CharField(max_length=20)
    description = models.TextField()
    is_public = models.BooleanField(default=False)

serializers.py

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo

views.py

class FooRetrieveAPIView(RetrieveAPIView):
    queryset = Foo.objects.all()
    serializer_class = FooSerializer

Now the result of this endpoint is being used by front-end code, which is then the basis on how the next page to show is identified. Anyway, I need to change the structure of the results returned for both status 200 (existing record) and 404 (non-existent record).

Actual result (from vanilla DRF):

$ curl localhost:8000/foo/1/  # existing record
{"id": 1, "name": "foo", "description": "foo description", is_public=false}

$ curl localhost:8000/foo/2/  # non-existent record
{"detail": "Not found."}

How I want the results to be:

$ curl localhost:8000/foo/1/
{"error": "", "foo": {"id": 1, "name": "foo", "description": "foo description", is_public=false}}

$ curl localhost:8000/foo/2/
{"error": "Some custom error message", "foo": null}

I've mostly used vanilla DRF so things are pretty straightforward so this customization of the response structure is a bit new to me.

Django version used: 1.9.9

DRF version used: 3.3.x

Usman Maqbool
  • 3,351
  • 10
  • 31
  • 48
baktin
  • 153
  • 1
  • 5
  • Possible duplicate of http://stackoverflow.com/questions/35019030/how-to-return-custom-json-in-django-rest-framework – JClarke Aug 22 '16 at 15:55

2 Answers2

5

You can rewrite retrieve method in your view in order to update your serializer response data

class FooRetrieveAPIView(RetrieveAPIView):
    queryset = Foo.objects.all()
    serializer_class = FooSerializer

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        # here you can manipulate your data response
        return Response(data)
levi
  • 22,001
  • 7
  • 73
  • 74
  • 1
    Thanks. This worked for the `200` response. I needed to do some exception handling to get the `404` response right. – baktin Aug 22 '16 at 23:31
2

I had a similar problem and didn't want to create a custom exception handler as I wanted more control over defining error messages for api calls. After a bit of hand banging I used the following code in viewset to get custom error message while updating the record using partial_update.

 def partial_update(self, request, *args, **kwargs):
    partial = kwargs.pop('partial', False)
    try:
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        headers = self.get_success_headers(serializer.data)
        response = {"status": "True", "message": "", "data": serializer.data}
        return Response(response, status=status.HTTP_201_CREATED, headers=headers)
    except exception.Http404:
        headers = ""
        response = {"status": "False", "message": "Details not found", "data": ""}
        return Response(response, status=status.HTTP_200_OK, headers=headers)