Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customize Status code response from Django Rest Framework serializer

The scenario is quite straight-forward:

Say i have a user model where email should be unique. I did a custom validation for this like.

def validate_email(self, value):
    if value is not None:
        exist_email = User.objects.filter(email=value).first()
        if exist_email:
            raise serializers.ValidationError("This Email is already taken")
    return value

from rest_framework response when input validation occur we should return status_code_400 for BAD_REQUEST but in this scenario we should or we need to return status_code_409 for conflicting entry. What is the best way to customize status_code response from serializer_errors validation.

like image 639
Shakil Avatar asked Oct 23 '25 08:10

Shakil


1 Answers

I think is better to define custom exception_handler like:

settings.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'myproject.common.custom_classes.handler.exception_handler',
}

handler.py

def exception_handler(exc, context):
    # Custom exception hanfling
    if isinstance(exc, UniqueEmailException):
        set_rollback()
        data = {'detail': exc.detail}
        return Response(data, status=exc.status_code)

    elif isinstance(exc, (exceptions.APIException, ValidationError)):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if hasattr(exc, 'error_dict') and isinstance(exc, ValidationError):
            exc.status_code = HTTP_400_BAD_REQUEST
            data = exc.message_dict
        elif isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    elif isinstance(exc, Http404):
        msg = _('Not found.')
        data = {'detail': six.text_type(msg)}

        set_rollback()
        return Response(data, status=status.HTTP_404_NOT_FOUND)

    return None

exceptions.py

class UniqueEmailException(APIException):
    status_code = status.HTTP_409_CONFLICT
    default_detail = 'Error Message'

And finally the validator:

def validate_email(self, value):
    if value is not None:
        exist_email = User.objects.filter(email=value).first()
        if exist_email:
            raise UniqueEmailException()
    return value
like image 60
Mau Avatar answered Oct 24 '25 23:10

Mau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!