Search code examples
djangorestapidjango-rest-frameworkhttp-status-codes

Django REST framework: how to respond with useful error messages with get_queryset()


I have a django model which I want to display via Django Rest framework. I am getting all objects in the model to be displayed via the get_queryset(). However, I also have a couple of query_params which will filter out certain objects. This is my main code which is working fine:

class PlanView(generics.ListAPIView):
    """
    API endpoint which allows prices to be viewed or edited
    """

    serializer_class = PlanSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)

    # override method
    def get_queryset(self):
        //get all objects in Plan model
        queryset = Plan.objects.all()

        // possible query parameters to be read from url
        size = self.request.query_params.get("size", None)
        price = self.request.query_params.get("price", None)

        if size is not None:
            if size == "large":
                queryset = queryset.filter(Large=True)
            elif size == "small":
                queryset = queryset.filter(Large=False)

        if price is not None:
            queryset = queryset.filter(price=price)

        return queryset

with this urlpattern:

path(r'API/plans', views.PlanView.as_view(), name='prices'),

The only problem is that when I purposefully write the below URL in a browser,

http://127.0.0.1:8000/API/plans?size=sm

which has a bad/misspelled query_param value, the get_query() code will just ignore it and display the objects as if there are no filters.

I tried to put an else statement such as:

    if size is not None:
            if size == "large":
                queryset = queryset.filter(Large=True)
            elif size == "small":
                queryset = queryset.filter(Large=False)
            else:
                return Response({"Error":"bad request"}, status=status.HTTP_400_BAD_REQUEST)

but with this, I get an error message saying:

ContentNotRenderedError at /API/plans
The response content must be rendered before it can be iterated over.

How can I display useful error responses/jsons if a user puts in a wrong parameter value in the API?


Solution

  • You can use ValidationError

    from rest_framework.exceptions import ValidationError
    # ...
            raise ValidationError(detail="size must be either 'large' or 'small'")
    

    DRF catches these exceptions and displays them neatly. It returns a JSON of the form

    {
        "detail": "size must be either 'large' or 'small'"
    }