In Django REST Framework, why does raising serializers.ValidationError return errors in different format in validate() and create() methods?

I am working on a DRF project and have a serializer like:

class SomeSerializer(serializers.Serializer):
    number_field = serializers.IntegerField(required=False, min_value=25, max_value=100)

In my settings.py, I have

REST_FRAMEWORK = { 
    other settings....     
    'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_handler', 
}

In the custom exception handler, I handle ValidationError as follows:


def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first
    response = exception_handler(exc, context)
    messages = None
    code = None
    detail = None

    if response is not None:
        # Map specific exceptions to custom error codes
        if isinstance(exc, ValidationError):
            code = "validation_error"
            detail = "One or more fields failed validation."
            messages = exc.detail
            status_code = status.HTTP_400_BAD_REQUEST
        # After checking for other errors here in between
        else:
            code = "unexpected_error"
            detail = response.data.get("detail", "An unexpected error occurred.")
            messages = response.data.get("messages", {"error": str(exc)})
"""
In between the if and else, AuthenticationFailed, PermissionDenied, NotFound, are handled. Add an appropriate code and return in the format
response.data = {
            "detail": detail,
            "code": code,
            "messages": messages
        }
"""

The custom exception handler is configured to return the error in the format shown below. But it only happens if I validate the min and max range inside the create() method (without min_value and max_value defined on the serializer field itself)

{
    "detail": "One or more fields failed validation.",
    "code": "validation_error",
    "messages": {
        "number_field": [
            "Ensure this value is greater than or equal to 25."
        ]
    }
}

But if I leave the validation to min_value and max_value specified on the serializer field, or even if I manually validate it inside validate method, or a validate_number_field method, it is returned in the original DRF format

{
    "number_field": [
        "Ensure this value is greater than or equal to 25."
    ]
}

One way to get the error format from the custom exception handler with min_value and max_value defined on the serializer field was to override the to_internal_value method and handle ValidationError there.

def to_internal_value(self, data):
    try:
        return super().to_internal_value(data)
    except serializers.ValidationError as exc:
        raise serializers.ValidationError({
            "detail": "One or more fields failed validation.",
            "code": "validation_error",
            "messages": exc.detail
        })

But for me, this defeats the purpose of having a custom exception handler. If I want this behaviour project-wide, what options do I have other than subclassing serializers.Serializer (or ModelSerializer) and overriding the to_internal_value method.

Вернуться на верх