django 如何在DRF中的串行器验证功能中将404作为状态代码发出?

w7t8yxp5  于 2023-01-27  发布在  Go
关注(0)|答案(2)|浏览(120)

我在串行器中编写了一个validate()函数。默认情况下,Serializer Errors返回400作为状态代码。但是我想返回404。我尝试了以下操作:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MyClass
        fields = "__all__"

    def validate(self, data):
        current_user = self.context.get("request").user
        user = data.get("user")
        if user!=current_user:
            raise ValidationError({'detail': 'Not found.'}, code=404)
        return data

但是它仍然返回400作为状态码的响应,怎么做呢?

t40tm48m

t40tm48m1#

这是处理验证错误的Django源代码。

def is_valid(self, *, raise_exception=False):
        # This implementation is the same as the default,
        # except that we use lists, rather than dicts, as the empty case.
        assert hasattr(self, 'initial_data'), (
            'Cannot call `.is_valid()` as no `data=` keyword argument was '
            'passed when instantiating the serializer instance.'
        )

        if not hasattr(self, '_validated_data'):
            try:
                self._validated_data = self.run_validation(self.initial_data)
            except ValidationError as exc:
                self._validated_data = []
                self._errors = exc.detail
            else:
                self._errors = []

        if self._errors and raise_exception:
            raise ValidationError(self.errors)

        return not bool(self._errors)

Django会检查ValidationError,然后从错误对象中获取详细信息,并使用状态码400重新创建,这就是代码无法工作的原因。
因此,从视图类中捕获django错误并更改状态代码,如下所示。

class NotesList(mixins.CreateModelMixin, mixins.ListModelMixin, generics.GenericAPIView):
    serializer_class = MySerializer

    def get_queryset(self):
        return models.MyClass.objects.filter(owner=self.request.user)

    def post(self, request):
        try:
            return self.create(request)
        except ValidationError as exc:
            exc.status_code = 404
            raise exc
txu3uszq

txu3uszq2#

您可以通过处理序列化验证从视图中执行此操作:

class MySerializer(serializers.ModelSerializer):

    class Meta:
        model = models.MyClass
        fields = "__all__"

    def validate(self, data):
        current_user = self.context.get("request").user
        user = data.get("user")
        if user != current_user:
            raise serializers.ValidationError(
                {'detail': 'Not found.'},
                code=404,
            )
        return data

class MyView(APIView):

    def post(self, request):
        serializer = MySerializer(
            data=request.data,
            context={'request': request},
        )
        if not serializer.is_valid():
            return Response(serializer.errors, status=404)
        return Response(serializer.data)

或者,您也可以通过定义自己的异常处理程序来完成此操作:

def my_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None and response.status_code == 400:
        response.status_code = 404
    return response

class MyView(APIView):
    exception_handler = my_exception_handler

    def post(self, request):
        serializer = MySerializer(
            data=request.data, 
            context={'request': request},
        )
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data)

但正如您所说,如果您想从序列化器中执行此操作,则必须定义自定义异常并从序列化器中引发它:

class NotFoundError(serializers.ValidationError):
    def __init__(self, detail):
        super().__init__(detail, code=404)

class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MyClass
        fields = "__all__"

    def validate(self, data):
        current_user = self.context.get("request").user
        user = data.get("user")
        if user != current_user:
            raise NotFoundError({'detail': 'Not found.'})
        return data

相关问题