Django REST Framework如何在序列化程序中引发验证错误时指定错误代码

Che*_*eng 14 django django-rest-framework

我有一个API端点,允许用户注册帐户.我想为重复的用户名返回HTTP 409而不是400.

这是我的序列化器:

from django.contrib.auth.models import User
from rest_framework.serializers import ModelSerializer

class UserSerializer(ModelSerializer):
    username = CharField()

    def validate_username(self, value):
        if User.objects.filter(username=value).exists():
            raise NameDuplicationError()
        return value


class NameDuplicationError(APIException):
    status_code = status.HTTP_409_CONFLICT
    default_detail = u'Duplicate Username'
Run Code Online (Sandbox Code Playgroud)

触发错误时,响应为:{"detail":"Duplicate Username"}.我意识到,如果我将APIException子类化,detail则使用密钥代替username.

我希望得到这个回应 {"username":"Duplicate Username"}

或者我想在引发ValidationError时指定状态代码:

def validate_username(self, value):
    if User.objects.filter(username=value).exists():
        raise serializers.ValidationError('Duplicate Username', 
                                          status_code=status.HTTP_409_CONFLICT)
    return value
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为ValidationError只返回400.

有没有其他方法可以实现这一目标?

Anu*_*dra 26

你可以提出不同的例外,例如:

from rest_framework.exceptions import APIException
from django.utils.encoding import force_text
from rest_framework import status


class CustomValidation(APIException):
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    default_detail = 'A server error occurred.'

    def __init__(self, detail, field, status_code):
        if status_code is not None:self.status_code = status_code
        if detail is not None:
            self.detail = {field: force_text(detail)}
        else: self.detail = {'detail': force_text(self.default_detail)}
Run Code Online (Sandbox Code Playgroud)

您可以在序列化程序中使用它,如:

raise CustomValidation('Duplicate Username','username', status_code=status.HTTP_409_CONFLICT)
Run Code Online (Sandbox Code Playgroud)

要么

raise CustomValidation('Access denied','username', status_code=status.HTTP_403_FORBIDDEN)
Run Code Online (Sandbox Code Playgroud)


Omi*_*aha 17

默认情况下,加注serializers.ValidationError将返回HTTP_400_BAD_REQUEST

但有时我们希望返回 ValidationError正常的200状态代码,因为客户端的某些库无法解析 json响应数据,而响应代码则不能200

我试过这个。但它没有起作用:

raise serializers.ValidationError({'message':'Invalid  email address'}, code=200)
Run Code Online (Sandbox Code Playgroud)

所以我们可以这样做并且它有效:

res = serializers.ValidationError({'message':'Invalid  email address'})
res.status_code = 200
raise res
Run Code Online (Sandbox Code Playgroud)