在 Django REST Framework 中找不到资源时如何 return 404

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

当用户输入错误的 url 时,我的 Django 应用 return 会出现 HTML 错误。我怎样才能让 DRF 变成 return 一个 json 格式错误?

目前我的url是

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),
]

但是如果用户转到 127.0.0.1:8000/snip 他们会得到 html 格式错误而不是 json 格式错误。

简单的方法,您可以使用 raise Http404,这是您的 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)

你也可以用Response(status=status.HTTP_404_NOT_FOUND)来处理,这个答案是如何处理的:

但之前,在你的 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)

为了测试它,一个使用curl命令的例子;

$ curl -X GET http://localhost:8000/snippets/<pk>/

# example;

$ curl -X GET http://localhost:8000/snippets/99999/

希望能帮到你..


更新

如果你想用 DRF 处理所有错误 404 url​​,DRF 也提供 APIException, this answer may help you;

我将举例说明如何使用它;

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

from rest_framework import status    
from rest_framework.response import Response

# return 404 status code    
return Response({'status': 'details'}, status=status.HTTP_404_NOT_FOUND)

或者简单地说,您可以使用相同的 DRF 结构,而不会丢失 I18N 并保持相同的 DRF 错误消息:

from rest_framework import viewsets, status, exceptions
from rest_framework.decorators import action
from rest_framework.response import Response

        try:

            codename = get_or_bad_request(self.request.query_params, 'myparam')
            return Response(self.get_serializer(MyModel.objects.get(myparam=codename), many=False).data)
        except MyModel.DoesNotExist as ex:
            exc = exceptions.NotFound()
            data = {'detail': exc.detail}
            return Response(data, exc.status_code)