Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework custom 404 error page

How to customize Django rest framework error page. Can't find about it. In my rest action code:

from django.http import Http404

class SomeAction(APIView):
    def get(self, *args, **kwargs):
        raise Http404()

I need to display custom error page in prod.

like image 592
strz Avatar asked Oct 19 '25 04:10

strz


2 Answers

from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import loader, RequestContext, Context
from apps.settings import DEBUG
from libs.requestprovider.middleware import get_current_request

from rest_framework.views import exception_handler



def custom_exception_handler(exc):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc)

    # Now add the HTTP status code to the response.
    if response is not None:
        response.data['status_code'] = response.status_code

    if not DEBUG:
        #errors can be more generic
        if response.data['status_code'] == 404:
            t = loader.get_template('404.html')
            c = RequestContext(get_current_request(), {})
            return HttpResponse(t.render(c), content_type="text/html")
    return response
like image 97
strz Avatar answered Oct 20 '25 19:10

strz


TL;DR

class YourAPIView(APIView):
    @staticmethod
    def my_exception_handler(exc, context):
        response = exception_handler(exc, context)
        if if response.status_code >= 400:
            return HttpResponse(loader.get_template('your.html').render(context), content_type='text/html')
        return response

    def get_exception_handler(self):
        return self.my_exception_handler

Long story

This link (custom-exception-handling) tells you to set EXCEPTION_HANDLER to yours, and you will notice that the default settings is rest_framework.views.exception_handler

Of course, you can follow the tutorial, but if you don't want to use global settings to control, then see the following.

I suggest you set breakpoints on the function (rest_framework.views.exception_handler) to see what is going on, and then you will know all proceeding.

If you don't want to debug, I list the key points below.

# rest_framework\views.py

class APIView(View):
    ...

    def dispatch(self, request, *args, **kwargs):
        ...
        try:
            ...
        except Exception as exc:
            response = self.handle_exception(exc)  # <-- focus here
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    
     def handle_exception(self, exc):
        ...
        exception_handler = self.get_exception_handler()  # <-- focus here
    
        context = self.get_exception_handler_context()
        response = exception_handler(exc, context)
        ...
        return response
    
    def get_exception_handler(self):
        return self.settings.EXCEPTION_HANDLER

From the above code, you know you can change get_exception_handler then all down!

here is an example:

# views.py

from rest_framework import generics
from django.http import HttpResponse
from rest_framework import status
from django.template import loader
from rest_framework.views import exception_handler


class YourAPIView(generics.ListAPIView):
    ...
    def get(self, request, *args, **kwargs):
        return HttpResponse('ok', content_type='text/html')

    @staticmethod
    def my_exception_handler(exc, context):
        response = exception_handler(exc, context)  # <-- this is the default exception_handler
        if response.status_code in (status.HTTP_400_BAD_REQUEST, status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN):
            my_400_and_403_template = loader.get_template('error.html')  #  settings.py -> TEMPLATES = [{'DIRS': [ str(Path(BASE_DIR)/Path('templates/your_custom_dir')).replace('\\', '/') ]}]  # Where your_custom_dir should contain error.html
            return HttpResponse(my_400_and_403_template.render(context), content_type='text/html')
        return response

    def get_exception_handler(self):
        return self.my_exception_handler

    # def handle_exception(self, exc):
    #    return super().handle_exception(exc)
like image 22
Carson Avatar answered Oct 20 '25 19:10

Carson



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!