Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model field length constraint with validation response in serializer

I am validating data from a request in django's rest framework with data validation in the serializer. I need all error messages to be sent in a single response.

On sending a string that is too long, i get the error:

django.db.utils.DataError: value too long for type character varying(3)

In my model I've defined the max length of the character field as 3 (max theoretically needed).

I've added validation in the serializer to catch requests with too many characters:

validators.py

class CustomUserValidators():

    errors_to_return = {}
    def val_role(self, role):
            if len(role) > 3:
                self.errors_to_return["role_length"] = "Ensure this field has no more than 3 characters."

serializers.py

from Sea.validators import CustomUserValidators
class LagoonUserCreateSerializer(UserCreateSerializer, CustomUserValidators):
    class Meta:
        model = User
        fields = ('id', 'username', 'role',)


    def validate(self, attrs):
        self.val_role(attrs['role'])

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

        return attrs

models.py

class SeaUser(AbstractUser):
    ...
    role = models.CharField(_('Role'), max_length=3)

But the request still returns the error (value too long... as above). I expected the erorr to be caught in the serializer and the values not passed to the model, why is the value ever reaching the model?

I have researched this, and all the solutions say make the field length 255. This doesn't answer why the value is ever being tested by the model in the first place, and doesn't explain what happend if somehow a longer than expected value does end up in the request.

Any help with this is appreciated.

like image 984
Preston Avatar asked Oct 16 '22 13:10

Preston


1 Answers

I would go with different approach and take advantage of serializer's validation.

You can specify custom field-level validation by adding .validate_field methods to your Serializer.

So you can add the following method to your serializer.

def validate_role(self, value):
    if len(value) > 3:
        raise serializers.ValidationError("Ensure this field has no more than 3 characters")
    return value

And remove CustomUserValidators completely.

As mentioned in the comment, you can move the validation to a utility function and use it everywhere you need.

def validate_user_role(value):
    return 0 < len(value) <= 3

You can place this function in a separete module if you like and then you use in your serializer:

def validate_role(self, value):
    if not validate_user_role(value):
        raise serializers.ValidationError("Ensure this field has no more than 3 characters")
    return value

Another, simpler solution to consider is to use serializer's CharField attributes and do this:

class LagoonUserCreateSerializer(UserCreateSerializer):
    role = serializers.CharField(min_length=1, max_length=3)

This will validate your input without implementing the validate_role method.

like image 137
Enthusiast Martin Avatar answered Oct 21 '22 00:10

Enthusiast Martin