DRF 中如何立即返回所有序列化器错误?

bin*_*nny 5 django django-serializer django-rest-framework

我正在测试 中引发的多个验证错误(UserRegistrationSerializer)。但 DRF 仅返回引发的第一个错误: {'username': [ErrorDetail(string='Choose a different username', code='invalid')]}

我期待:{'username': [ErrorDetail(string='选择不同的用户名', code='invalid')], 'password2': [ErrorDetail(string='密码确认失败', code='invalid' )]

一旦序列化器被验证(如文档示例中所示),如何解释多个错误?

https://www.django-rest-framework.org/api-guide/serializers/#validation

class TestRegisterationSerializer__002(TestCase):
    '''Verify that the registeration process fails with respect
    to selecting an unavailable username and password confirmation'''

    @classmethod
    def setUpTestData(cls):
        User.objects.create_user(username="Python")
        cls.data = {
            'username': "Python",
            'password': "#secret#",
            'password2': "Secret"
        }
        cls.error_messages = [
            "Choose a different username", "Password confirmation failed"
        ]
        cls.serializer = UserRegisterationSerializer(data=cls.data)

    def test_user_registeration_invalid_confirmation(self):
        self.serializer.is_valid()
        print(self.serializer.errors)
Run Code Online (Sandbox Code Playgroud)
import re

from django.contrib.auth.models import User

from rest_framework import serializers


class UsernameSerializer(serializers.ModelSerializer):

    username = serializers.SlugField(min_length=4, max_length=12)

    def validate_username(self, value):
        try:
            self.Meta.model.objects.get(username__iexact=value)
        except self.Meta.model.DoesNotExist:
            return value
        raise serializers.ValidationError("Choose a different username")

    class Meta:
        fields = ['username', ]
        model = User


class LoginSerializer(UsernameSerializer):

    password = serializers.RegexField(
        r"[0-9A-Za-z]+", min_length=5, max_length=8
    )

    def validate(self, data):
        username, password = [
            input.lower() for input in [data['username'], data['password']]
        ]
        if all(password[i] == password[i + 1] for i in range(len(password) - 1)) or username == password:
            raise serializers.ValidationError({
                'password': "Invalid password"
            })
        return data

    class Meta:
        fields = ['username', 'password', ]
        model = User


class UserRegistrationSerializer(LoginSerializer):

    password2 = serializers.RegexField(
        r"[0-9A-Za-z]+", min_length=5, max_length=8, write_only=True
    )

    def validate(self, data):
        data = super().validate(data)
        if data['password'] != data['password2']:
            raise serializers.ValidationError({"password2": "Password confirmation failed"})
        return data

    class Meta:
        model = User
        fields = ['username', 'password', 'password2']


Run Code Online (Sandbox Code Playgroud)

小智 2

请删除 UsernameSerializer 和 LoginSerializer 中 validate 方法的自定义,并将该方法放置在 UserRegistrationSerializer 中

from rest_framework.exceptions import ValidationError

def validate(self, data):
    errors = []
    data = super().validate(data)
    username = data.get("username")
    if self.Meta.model.objects.filter(username__iexact=username).exists():
       errors.append({"username":"Choose a different username"})

    username, password = [
            input.lower() for input in [data['username'], data['password']]
        ]
    if all(password[i] == password[i + 1] for i in range(len(password) - 1)) or username == password:
        errors.append({
            'password': "Invalid password"
        })
    
    if data['password'] != data['password2']:
        errors.append({"password2": "Password confirmation failed"})

    if errors:
        raise serializers.ValidationError(errors)
    return data
Run Code Online (Sandbox Code Playgroud)