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
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 :
- By email at [email protected].
- If you want to know more about me, you can check out my about page.
You can use my articles with no cost or attribution, feel free to edit them and make them your own.