Django REST 框架:如何使用 get_queryset() 响应有用的错误消息
Django REST framework: how to respond with useful error messages with get_queryset()
我有一个 Django 模型,我想通过 Django Rest 框架显示它。我正在让模型中的所有对象通过 get_queryset()
显示。但是,我还有几个 query_params
可以过滤掉某些对象。这是我的主要代码,运行良好:
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
具有 bad/misspelled query_param
值,get_query() 代码将忽略它并像没有过滤器一样显示对象。
我试着写一个 else 语句,例如:
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 中输入错误的参数值,我如何显示有用的错误 responses/jsons?
您可以使用ValidationError
from rest_framework.exceptions import ValidationError
# ...
raise ValidationError(detail="size must be either 'large' or 'small'")
DRF 捕获这些异常并整齐地显示它们。它 returns 一个 JSON 形式
{
"detail": "size must be either 'large' or 'small'"
}
有两种方法可以处理此问题:1)
手动验证或 2)
使用 django-filters
程序包。
1) 手动引发 ValidationError(最简单)
if size not in ['small', 'large']:
raise ValidationError(f"Invalid size {size}. Please use small/large")
else:
# filter normally. remember to consider the '' value
2) 使用django-filters(最佳)
过滤器可帮助您将过滤和排序逻辑与视图集分开,并且无需手动 check/parse/validate 输入数据。在 ChoiceFilter
(docs) 的情况下,它还会验证输入并为您引发错误。
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()
看看你的模式,如果这个问题是准确的,你也可以使用过滤器包中记录的方法或者 BooleanFilter
如果你将名称更改为 is_large
,例如is_large=True
.
我有一个 Django 模型,我想通过 Django Rest 框架显示它。我正在让模型中的所有对象通过 get_queryset()
显示。但是,我还有几个 query_params
可以过滤掉某些对象。这是我的主要代码,运行良好:
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
具有 bad/misspelled query_param
值,get_query() 代码将忽略它并像没有过滤器一样显示对象。
我试着写一个 else 语句,例如:
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 中输入错误的参数值,我如何显示有用的错误 responses/jsons?
您可以使用ValidationError
from rest_framework.exceptions import ValidationError
# ...
raise ValidationError(detail="size must be either 'large' or 'small'")
DRF 捕获这些异常并整齐地显示它们。它 returns 一个 JSON 形式
{
"detail": "size must be either 'large' or 'small'"
}
有两种方法可以处理此问题:1)
手动验证或 2)
使用 django-filters
程序包。
1) 手动引发 ValidationError(最简单)
if size not in ['small', 'large']:
raise ValidationError(f"Invalid size {size}. Please use small/large")
else:
# filter normally. remember to consider the '' value
2) 使用django-filters(最佳)
过滤器可帮助您将过滤和排序逻辑与视图集分开,并且无需手动 check/parse/validate 输入数据。在 ChoiceFilter
(docs) 的情况下,它还会验证输入并为您引发错误。
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()
看看你的模式,如果这个问题是准确的,你也可以使用过滤器包中记录的方法或者 BooleanFilter
如果你将名称更改为 is_large
,例如is_large=True
.