如何使用 DRF APIView 获取方法和 ModelSerializer 的 return 400 状态码?

How can one return 400 status code with DRF APIView get method and ModelSerializer?

我有以下代码(用于端点 /things/{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) 方法 returns 布尔值。这适用于正确的请求,但我想添加一种方法来验证请求并为客户端错误发送适当的状态代码,例如 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 方法以使其正常工作。

有什么想法吗?

感谢您抽出宝贵的时间!

.validate() 方法接受一个参数,它是字段值的字典。如有必要,它应该引发 ValidationError,或者只是 return 验证值。
实现此目的的方法之一是将 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)


我的建议

如果您从数据库序列化对象,大多数时候它不会引发任何验证错误。我建议,如果 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)

我使用了你的"suggestion",但我不得不修改最后一行。我替换了:

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

作者:

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

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