Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DjangoRestFramework ModelSerializer: field-level validation is not working

This is my serializers.py (I want to create a serializer for the built-in User model):

from rest_framework import serializers

from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('username', 'password', 'email', )

    def validate_username(self, username):
        if not re.search(r'^\w+$', username): #checks if all the characters in username are in the regex. If they aren't, it returns None
            raise serializers.ValidationError('Username can only contain alphanumeric characters and the underscore.')
        try:
            User.objects.get(username=username)
        except ObjectDoesNotExist:
            return username
        raise serializers.ValidationError('Username is already taken.')

The issue is, when I try to create a user using a username which already exists, it returns the following dictionary:

{'username': [u'This field must be unique.']}

rather than saying

{'username': [u'Username is already taken']}

I recreated the validate_username function to this (for testing purposes):

    def validate_username(self, username):
        raise serializers.ValidationError('Testing to see if an error is raised.')

and it doesn't raise an error. Any idea why DjangoRestFramework is ignoring the validate_username function?

Edit: Note that I am using a ModelSerializer (in the tutorial here: http://www.django-rest-framework.org/api-guide/serializers/#validation it talks about field-level validation only for a Serializer, not a ModelSerializer). Note sure if it makes a difference or not.

like image 566
SilentDev Avatar asked May 30 '15 04:05

SilentDev


1 Answers

Field-level validation is called before serializer-level validation.

So model User having username as unique=True, the field-level validation will raise exception because of username being already present. DRF's UniqueValidator does this work of raising exception when a field is not unique.

As per DRF source code,

class UniqueValidator:
    """
    Validator that corresponds to `unique=True` on a model field.

    Should be applied to an individual field on the serializer.
    """
    message = _('This field must be unique.')

Since these validators run before serializer-level validation, your validate_username is never called.

like image 165
Rahul Gupta Avatar answered Sep 19 '22 10:09

Rahul Gupta