如何使用DRF APIView get方法和ModelSerializer返回400状态代码?

时间:2018-02-22 20:17:14

标签: validation django-rest-framework http-status-codes

我有以下代码(针对端点/东西/ {id} / permission-to-do / 的 views.py

class PermissionsToDo(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    def get(self, request,*args,**kwargs):
        thing_id = kwargs.get('pk')
        thing = Thing.objects.filter(pk=thing_id,is_active=True)
        serializer = serializers.GetDoPermissionSerializer(thing[0],context={'request': request})
        return Response(serializer.data, status=status.HTTP_200_OK)

serializers.py

class serializers.GetDoPermissionSerializer(serializers.ModelSerializer):
    def _can_do(self, thing):
        return thing.can_be_done_by(self.context['request'].user)

    can_do = serializers.SerializerMethodField('_can_do')

    class Meta:
        model = Thing.objects.filter
        fields = ('can_do',)
        extra_kwargs = {
            'can_do': {'read_only': True},
        }

thing.can_be_done_by(user)方法返回一个布尔值。这适用于正确的请求,但我想添加一种方法来验证请求并发送适当的客户端错误状态代码,例如status.HTTP_400_BAD_REQUEST

我的想法只是添加 views.py a:

if serializer.is_valid():
    return Response(serializer.data, status=status.HTTP_200_OK)
else:
    return Response(SOMETHING?,status.HTTP_400_BAD_REQUEST)

如果我评估serializer.is_valid(),我会收到一条错误消息:

'Cannot call `.is_valid()` as no `data=` keyword argument was '
AssertionError: Cannot call `.is_valid()` as no `data=` keyword argument was passed when instantiating the serializer instance. 

如果我换行:

serializer = serializers.GetDoPermissionSerializer(thing[0],context={'request': request})

成:

serializer = serializers.GetDoPermissionSerializer(data=thing[0],context={'request': request})

然后,我得到一个错误,表明我应该将字典作为数据而不是对象传递。但后来我不确定如何实现validate方法以及如何更改_can_do方法以使其正常工作。

有什么想法吗?

感谢你的时间,如果你有空的话!

2 个答案:

答案 0 :(得分:1)

.validate()方法接受一个参数,该参数是字段值的字典。如有必要,它应该引发ValidationError,或者只返回经过验证的值 其中一种方法是将model object转换为dict。因此,请尝试以下代码段,

class PermissionsToDo(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        thing_id = kwargs.get('pk')
        thing = Thing.objects.filter(pk=thing_id, is_active=True)
        serializer = serializers.GetDoPermissionSerializer(data=thing[0].__dict__, context={'request': request})  # Change is here <<<<
        if serializer.is_valid():
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(SOMETHING?, status.HTTP_400_BAD_REQUEST)


我的建议

如果要从DB序列化对象,大多数情况下它不会引发任何验证错误。我建议,如果thing对象变为empty queryset,请尝试显示错误消息。所以,

class PermissionsToDo(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        thing_id = kwargs.get('pk')
        try:
            serializer = serializers.GetDoPermissionSerializer(Thing.objects.get(id=thing_id), context={'request': request})
            return Response(serializer.data, status=status.HTTP_200_OK)
        except Thing.DoesNotExist:
            return Response(data="object not found", status.HTTP_400_BAD_REQUEST)

答案 1 :(得分:0)

我使用了你的建议&#34;除了我必须修改最后一行。我换了:

return Response(data="object not found", status.HTTP_400_BAD_REQUEST)

by:

return Response("object not found", status.HTTP_400_BAD_REQUEST)

或者我收到以下错误: SyntaxError: positional argument follows keyword argument