Django REST框架:如何使用get_queryset()响应有用的错误消息

Django REST框架:如何使用get_queryset()响应有用的错误消息,django,rest,api,django-rest-framework,http-status-codes,Django,Rest,Api,Django Rest Framework,Http Status Codes,我有一个django模型,我想通过django Rest框架显示它。我正在通过get\u queryset()显示模型中的所有对象。但是,我还有几个query\u参数,可以过滤掉某些对象。这是我的主要代码,工作正常: class PlanView(generics.ListAPIView): """ API endpoint which allows prices to be viewed or edited """ serializer_class = Pla

我有一个django模型,我想通过django Rest框架显示它。我正在通过
get\u queryset()
显示模型中的所有对象。但是,我还有几个
query\u参数
,可以过滤掉某些对象。这是我的主要代码,工作正常:

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
使用此
urlpattern

path(r'API/plans', views.PlanView.as_view(), name='prices'),
唯一的问题是,当我有意在浏览器中写入以下URL时

http://127.0.0.1:8000/API/plans?size=sm
它有一个错误的
query\u param
值,get\u query()代码将忽略它并显示对象,就像没有过滤器一样

我试着用另外一种说法,比如:

    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)
但这样一来,我会收到一条错误消息,上面说:

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

如果用户在API中输入了错误的参数值,如何显示有用的错误响应/json?

您可以使用
ValidationError

来自rest\u framework.exceptions导入验证错误
# ...
raise ValidationError(detail=“大小必须为“大”或“小”)
DRF捕获这些异常并将它们整齐地显示出来。它返回以下格式的JSON

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

您可以使用
ValidationError

来自rest\u framework.exceptions导入验证错误
# ...
raise ValidationError(detail=“大小必须为“大”或“小”)
DRF捕获这些异常并将它们整齐地显示出来。它返回以下格式的JSON

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

有两种方法可以处理此问题:手动验证或使用现在本机支持DRF的
django filters

1)在这种情况下引发ValidationError(最简单)

2)使用(最佳)

过滤器可帮助您将过滤和排序逻辑与视图集分离,并消除手动检查/解析/验证传入数据的需要。如果是
选择过滤器
(),它还将验证输入并为您引发错误

from django_filters import TypedChoiceFilter
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
from rest_framework.fields import CharField
from rest_framework.generics import ListAPIView
from rest_framework.permissions import AllowAny
from rest_framework.serializers import ModelSerializer


class MyFilter(FilterSet):
    # this will return a 400/validation error if not a or b
    # but it will ignore blank.
    size = TypedChoiceFilter(
        field_name='Large', # your column name was 'Large'
        choices=[('small', 'Small'), ('large', 'Large')],
        convert=lambda value: value == 'large'  # true if value is Large
    )

class MyView(ListAPIView):
    filter_backends = [DjangoFilterBackend]
    filter_class = MyFilter
    ...

    def get_queryset(self):
        return TheModel.objects.all()


查看您的模式,如果这个问题是准确的,您还可以使用filters包中记录的方法,或者如果您将名称更改为
is_large
,则可以使用
BooleanFilter
,例如,
is_large=True

有两种方法来处理此问题:手动验证或使用现在本机支持DRF的
django过滤器

1)在这种情况下引发ValidationError(最简单)

2)使用(最佳)

过滤器可帮助您将过滤和排序逻辑与视图集分离,并消除手动检查/解析/验证传入数据的需要。如果是
选择过滤器
(),它还将验证输入并为您引发错误

from django_filters import TypedChoiceFilter
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
from rest_framework.fields import CharField
from rest_framework.generics import ListAPIView
from rest_framework.permissions import AllowAny
from rest_framework.serializers import ModelSerializer


class MyFilter(FilterSet):
    # this will return a 400/validation error if not a or b
    # but it will ignore blank.
    size = TypedChoiceFilter(
        field_name='Large', # your column name was 'Large'
        choices=[('small', 'Small'), ('large', 'Large')],
        convert=lambda value: value == 'large'  # true if value is Large
    )

class MyView(ListAPIView):
    filter_backends = [DjangoFilterBackend]
    filter_class = MyFilter
    ...

    def get_queryset(self):
        return TheModel.objects.all()


查看您的模式,如果这个问题是准确的,您还可以使用filters包中记录的方法,或者如果您将名称更改为
is_large
,则可以使用
BooleanFilter
,例如
is_large=True

如果您确实需要手动提高它,则应该提高
验证错误<代码>APIException
是500(服务器错误,而不是验证错误/400)。
code
参数不是HTTP状态,它是一个字符串,在值序列化到客户端之前,只能在
ErrorDetail
对象中访问。@AndrewBacker你说得对,我更改了答案以反映这一点。如果你真的需要手动提高它,你应该提高一个
ValidationError
<代码>APIException是500(服务器错误,而不是验证错误/400)。
code
参数不是HTTP状态,它是一个字符串,在值序列化到客户端之前,只能在
ErrorDetail
对象中访问。@AndrewBacker你说得对,我更改了答案以反映这一点。