When you use Django Rest Framework, one of the great features that make DRF so powerful is the Browsable API. It allows you to navigate through your API and test it directly from your browser with a powerful form, queryset filter and much more.

Even better, when enabled, you can use Django Debug Toolbar to optimize your API and see how many queries are generated like you would do with a normal Django view.

The problem

Sometimes the form is not needed, for me the two use cases are:

  • You want to use Django Debug Toolbar to optimize your API, but the form generate a lot of queries and make the debug toolbar hard to read.

  • You want to keep the Browsable API for your users and partners, but you don’t want them to be able to create or update data directly from the API.

To be fair the first one was really annoying to me since I did not know at first what was causing so many related queries even though I was using select_related and prefetch_related in my viewsets.

The second one is more of a convenience, since I can easily share a production ready API with my partners and they can test it directly from their browser, but I don’t want them to be able to create or update data directly from the API.

Remove the form

To understand the problem, let’s take a look at two screenshots of the Browsable API, one with the form and one without.

With the form

With the form

Without the form

Without the form

As you can see from the debug toolbar, the form is generating a lot of queries, making it unnecessary slow and hard to read.

To remove the form, you need to create a custom renderer and replace the default one.

The solution (with code)

What I did is create a custom renderer in the utils folder of my Django project, and then replace the default renderer in the settings.py file.

renderers.py

from rest_framework.renderers import BrowsableAPIRenderer

class BrowsableAPIRendererWithoutForms(BrowsableAPIRenderer):
    """Renders the browsable api, but excludes the forms."""

    def get_context(self, *args, **kwargs):
        ctx = super().get_context(*args, **kwargs)
        ctx["display_edit_forms"] = False
        return ctx

    def show_form_for_method(self, view, method, request, obj):
        """We never want to do this! So just return False."""
        return False

    def get_rendered_html_form(self, data, view, method, request):
        """Why render _any_ forms at all. This method should return
        rendered HTML, so let's simply return an empty string.
        """
        return ""

settings.py


REST_FRAMEWORK = {
   "DEFAULT_RENDERER_CLASSES": [
        "rest_framework.renderers.JSONRenderer",
        # "rest_framework.renderers.BrowsableAPIRenderer", # Old renderer
        "frontdesk.utils.renderers.BrowsableAPIRendererWithoutForms", # New renderer
    ],
}

Now the form is gone, the debug toolbar is much more readable and the API is read-only.


I hope this article was helpful, if you have any question or suggestion, feel free to reach out to me on :

You can use my articles with no cost or attribution, feel free to edit them and make them your own.