Custom error messages and custom validation

I read and understood in the documentation that it is possible to make custom validations for the model serializer class. However I don’t know how to catch the custom error message. I created the custom error messages and raise them in the validate_request() method in the UserPostSerializer class but the message I include doesn’t go to the serializer.errors in the view method for POST

This is what I’ve brewed up while testing this. It does raise the exception but it doesn’t give me the message which I included in the serializer class:

class UsersAPIview(APIView):
    def post(self, request):
        mydata = request.data
        serializer = UserPostSerializer(data=mydata)
        if serializer.is_valid():
            try:
                #Calling my custom validation method
                serializer.validate_request(mydata) #Should raise my custom ValidationError
            except ValidationError: 
                #serializer.errors only works after calling is_valid()
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 
                #I want to return my custom error message here but it's returning an empty dict {} instead.
                
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
    
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

This is the serializer class for the view:

class UserPostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = ['username', 'password']

    def validate_request(self, request_data):
        """This is my custom validation method"""
        #Validate attributes
        list_keys = request_data.keys()
        if len(list_keys)!=2:
            raise serializers.ValidationError({'Error':'Invalid attributes'})
        try:
            pw = request_data['password']
            usn = request_data['username']
        except:
            raise serializers.ValidationError({'Error':'Request must have password and username'})

        #Custom length validation for testing purposes
        if len(pw)<5 or len(usn)<5:
            raise serializers.ValidationError({'Error':'Pw and usn must have length <5'})

        return

UPDATE:
I’ve resorted to returning integers in the custom validation and storing a dict in the view to access custom errors.

The issue you’re facing is due to how you’re manually calling the validate_request method and handling the exception. The standard approach for custom validations in Django REST Framework (DRF) serializers is to define custom validation methods that DRF will automatically call during the is_valid method.

In your view, you don’t need to manually call the validate_request method. Instead, just call is_valid and handle errors based on the result of this call.

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import ValidationError
from .serializers import UserPostSerializer

class UsersAPIview(APIView):
    def post(self, request):
        mydata = request.data
        serializer = UserPostSerializer(data=mydata)
        
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        
        # This will capture the validation errors including custom ones
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

You should define custom validation methods in your serializer. DRF will automatically call these methods when is_valid is called.

from rest_framework import serializers
from .models import Users

class UserPostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = ['username', 'password']

    def validate(self, data):
        """
        Custom validation logic for the whole serializer.
        """
        # Check that both username and password are present
        if 'username' not in data or 'password' not in data:
            raise serializers.ValidationError({'Error': 'Request must have password and username'})

        # Custom length validation
        if len(data['password']) < 5 or len(data['username']) < 5:
            raise serializers.ValidationError({'Error': 'Pw and usn must have length >= 5'})

        return data

Thanks! I am sure I figured something out in the 4 years that have gone by but maybe your answer will help someone else :smile:

I wasn’t paying attention. I hope it will help those who have the same problem :smile: