Django Rest Framework (DRF) provides several built-in exceptions to handle common API errors, but it’s also possible to define your own custom exceptions or User-defined exceptions to handle specific error scenarios.

To define a User-defined exception in DRF, create a new module or file. Define the exception class in that file. For example, you could create a new file called exceptions.py and define a custom exception class like this:

from rest_framework.exceptions import APIException

class CustomException(APIException):
    status_code = 400
    default_detail = 'A custom exception has occurred.'

    def __init__(self, detail=None, code=None):
        if detail is not None:
            self.detail = detail
        else:
            self.detail = self.default_detail

        if code is not None:
            self.code = code

In this example, CustomException is defined as a subclass of APIException, which is the base exception class used by DRF. The status_code attribute is set to 400, which is the HTTP status code that will be returned when this exception is raised. The default_detail attribute provides a default error message that will be used if a more specific error message is not provided when the exception is raised.

When raising the CustomException class, you can pass in a custom error message and error code through its init method. Otherwise, the system will use the default message if you do not provide a custom one.

from rest_framework.views import APIView
from .exceptions import CustomException

class MyView(APIView):
    def get(self, request):
        if not request.user.is_authenticated:
            raise CustomException(detail='You must be logged in to access this resource.')
        # rest of view logic

If the user is not authenticated, the CustomException is raised with a specific error message that explains the issue. DRF then raises an exception and returns an HTTP response that includes the error message and status code.

A simple project on User-defined exceptions in Django Rest FrameWork

Assuming you already have Django and DRF installed, follow these steps:

1. Create a new Django project and app

django-admin startproject custom_exceptions_project
cd custom_exceptions_project
python manage.py startapp custom_exceptions_app

2. Add rest_framework and your app to the INSTALLED_APPS list in settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'custom_exceptions_app',
]

3. Create a new file exceptions.py in your app directory and define a custom exception class.

from rest_framework.exceptions import APIException

class CustomException(APIException):
    status_code = 400
    default_detail = 'A custom exception has occurred.'

    def __init__(self, detail=None, code=None):
        if detail is not None:
            self.detail = detail
        else:
            self.detail = self.default_detail

        if code is not None:
            self.code = code

4. Create a new file views.py in your app directory and define a DRF view that raises the custom exception

from rest_framework.views import APIView
from rest_framework.response import Response
from .exceptions import CustomException

class MyView(APIView):
    def get(self, request):
        if not request.user.is_authenticated:
            raise CustomException(detail='You must be logged in to access this resource.')
        return Response({'message': 'Success!'})

5. Add a URL route to your app’s urls.py file that maps to the view

from django.urls import path
from .views import MyView

urlpatterns = [
    path('myview/', MyView.as_view()),
]

6. Run the Django development server and test the view

python manage.py runserver

If you open a web browser and navigate to http://localhost:8000/myview/, you will encounter a CustomException with a 400 status code and error message “You must be logged in to access this resource.” because you are not logged in.

That’s it! This is a very simple example, but you can customize the CustomException class and use it in more complex scenarios as needed.