Search code examples
djangodjango-rest-frameworkhttp-status-code-404

How do you return 404 when resource is not found in Django REST Framework


When a user inputs a url that is wrong, my Django app returns an HTML error. How can I get DRF to return a json formatted error?

Currently my urls is

from django.conf.urls import url
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]

but if a user goes to 127.0.0.1:8000/snip They get the html formatted error rather than a json formatted error.


Solution

  • Simply way to do it, you can use raise Http404, here is your views.py

    from django.http import Http404
    
    from rest_framework import status
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    from yourapp.models import Snippet
    from yourapp.serializer import SnippetSerializer
    
    
    class SnippetDetailView(APIView):
    
        def get_object(self, pk):
            try:
                return Snippet.objects.get(pk=pk)
            except Snippet.DoesNotExist:
                raise Http404
    
        def get(self, request, pk, format=None):
            snippet = self.get_object(pk)
            serializer = SnippetSerializer(snippet)
            return Response(serializer.data, status=status.HTTP_200_OK)
    

    You also can handle it with Response(status=status.HTTP_404_NOT_FOUND), this answer is how to do with it: https://stackoverflow.com/a/24420524/6396981

    But previously, inside your serializer.py

    from rest_framework import serializers
    
    from yourapp.models import Snippet
    
    
    class SnippetSerializer(serializers.ModelSerializer):
        user = serializers.CharField(
            source='user.pk',
            read_only=True
        )
        photo = serializers.ImageField(
            max_length=None,
            use_url=True
        )
        ....
    
        class Meta:
            model = Snippet
            fields = ('user', 'title', 'photo', 'description')
    
        def create(self, validated_data):
            return Snippet.objects.create(**validated_data)
    

    To test it, an example using curl command;

    $ curl -X GET http://localhost:8000/snippets/<pk>/
    
    # example;
    
    $ curl -X GET http://localhost:8000/snippets/99999/
    

    Hope it can help..


    Update

    If you want to handle for all error 404 urls with DRF, DRF also provide about it with APIException, this answer may help you; https://stackoverflow.com/a/30628065/6396981

    I'll give an example how do with it;

    1. views.py

    from rest_framework.exceptions import NotFound
    
    def error404(request):
        raise NotFound(detail="Error 404, page not found", code=404)
    

    2. urls.py

    from django.conf.urls import (
      handler400, handler403, handler404, handler500)
    
    from yourapp.views import error404
    
    handler404 = error404
    

    Makesure your DEBUG = False