DEV Community 👩‍💻👨‍💻

Lina Rudashevski
Lina Rudashevski

Posted on

Creating Custom Exceptions using Django Rest Framework

Serialization errors returned by Django Rest Framework are not simple for the frontend to display, IMO. Here is how it return serialization errors for common user signup errors:

{'username': ['This field is required.'], 'password': ['This field must be at least 8 chars'], 'email': ['This field cannot be blank']}

Enter fullscreen mode Exit fullscreen mode

I find this hard for the frontend to have to handle. It might have to do a lot of work to say which field the error message relates to. It's also cumbersome for the frontend to parse a bunch of arrays for errors.

To make the error messages friendlier:

First, override the default error messages in the __init__ method of your serializer. Here I am changing it so that it actually says what field (i.e. username instead of 'This field') the error is related to:

class UserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(required=True)
    username = serializers.CharField(required=True)
    password = serializers.CharField(min_length=8, required=True)

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

    def __init__(self, *args, **kwargs):
        super(UserSerializer, self).__init__(*args, **kwargs)
        self.fields["username"].error_messages["required"] = u"username is required"
        self.fields["username"].error_messages["blank"] = u"username cannot be blank"
        self.fields["email"].error_messages["required"] = u"email is required"
        self.fields["email"].error_messages["blank"] = u"email cannot be blank"
        self.fields["password"].error_messages[
            "min_length"
        ] = u"password must be at least 8 chars"
Enter fullscreen mode Exit fullscreen mode

Then define the custom exception, which I did in a new file called exceptions.py. I am looking at the fields I might want to override an error and grabbing the first item in the array. If there are multiple exceptions per field, I'm not concerned because if the user fixes one, they'll graduate to the next exception.

from rest_framework.exceptions import ValidationError
from rest_framework.views import exception_handler


def base_exception_handler(exc, context):
    response = exception_handler(exc, context)

    # check that a ValidationError exception is raised
    if isinstance(exc, ValidationError):
        # here prepare the 'custom_error_response' and
        # set the custom response data on response object
        if response.data.get("username", None):
            response.data = response.data["username"][0]
        elif response.data.get("email", None):
            response.data = response.data["email"][0]
        elif response.data.get("password", None):
            response.data = response.data["password"][0]

    return response
Enter fullscreen mode Exit fullscreen mode

Finally, make sure to specify in your settings.py to use your new exception handler:

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "rest_framework.authentication.TokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
        "rest_framework.authentication.BasicAuthentication",
    ),
    "EXCEPTION_HANDLER": ("app.exceptions.base_exception_handler"),
}
Enter fullscreen mode Exit fullscreen mode

Here is the friendlier error message!
Alt Text

Top comments (2)

Collapse
okumujustine profile image
okumujustine

Save my time, thanks

Collapse
hamzzy profile image
hamzat • Edited on

Thank you Lina, your approach helped me.

Kudos

🌚 Life is too short to browse without dark mode