返回带有验证错误的单个响应,包括唯一的用户名约束

时间:2018-09-20 13:08:54

标签: django django-rest-framework

我想对包含无效数据的请求返回一个响应。

如果我重复一个用户名(发布一个已经在基础中的用户名[它是一个pk]),那么我会得到响应:

{
    "username": [
        "A user with that username already exists."
    ]
}

那太好了,但是如果我然后选择一个唯一的用户名,并且请求中存在其他错误,则会有以下响应:

{
    "gdpr_value_error": [
        "GDPR must be accepted"
    ],
    "role_value_error": [
        "Role must correspond to an existing role"
    ],
    "email": [
        "A user with that email already exists."
    ]
}

我想要这个:

{
    "gdpr_value_error": [
        "GDPR must be accepted"
    ],
    "role_value_error": [
        "Role must correspond to an existing role"
    ],
    "email": [
        "A user with that email already exists."
    ],
    "username": [
        "A user with that username already exists."
    ]
}

我的序列化器是:

class SeaUserCreateSerializer(UserCreateSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'first_name', 'last_name', 'role', 'gdpr', 'password',)

    def validate(self, attrs):
        errors_to_return = {}

        if attrs['gdpr'] != True:
            errors_to_return["gdpr_value_error"] = "GDPR must be accepted"

        CAPTAIN = 'cpt'
        CREW = 'crw'
        OTHER = 'oth'
        ROLE_CHOICES = {
            CAPTAIN: _('Captain'),
            CREW: _('Crew'),
            OTHER: _('Other'),
        }

        if attrs['role'] not in ROLE_CHOICES.keys():
            errors_to_return["role_value_error"] = "Role must correspond to an existing role"

        existing_usernames = User.objects.values_list('username', flat=True)
        if attrs['username'] in existing_usernames:
            errors_to_return["username"] = "A user with that username already exists."

        existing_emails = User.objects.values_list('email', flat=True)
        if attrs['email'] in existing_emails:
            errors_to_return["email"] = "A user with that email already exists."


        if len(errors_to_return) > 0:
            raise serializers.ValidationError(errors_to_return)

        return attrs

型号:

class SeaUser(AbstractUser):
    # Constants
    REQUIRED_FIELDS = ['email', 'first_name', 'last_name',]
    # Fields
    is_active = models.BooleanField(_('active'), default=False)
    email = models.EmailField(_('email address'))
    role = models.CharField(_('Role'), max_length=3)
    gdpr = models.BooleanField(_('GDPR'), default=False,)
    preferred_timezone = TimeZoneField(_('Preferred_timezone'), default='UTC',)
    def __str__(self):
        return self.email

我在heirachy类中搜索了错误消息,但是找不到用户名的验证位置(以及发生错误的位置)。

错误在哪里出现?重写该方法是一种好的做法,还是有一种更好的方法可以一起完成所有工作?

我尝试覆盖AbstractUser中的内置用户名:

username = models.CharField(
    _('username'),
    max_length=150,
    unique=True,
    help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
    validators=[username_validator],
    error_messages={
        'unique': _("A user with that username already exists."),
    },
)

使用

username = models.CharField(max_length=150)

但唯一性必须为true,这又在我需要它之前引发了validationError。

1 个答案:

答案 0 :(得分:1)

覆盖序列化器,使其看起来像:

assertThat(list1).comparingElementsUsing(resultOf(X::id)).containsExactlyElementsIn(list2);

这将从序列化器中删除唯一性验证器,并将检查交给您。