No Time Dad

A blog about web development written by a busy dad

Example Django External HTTP Request

Recently I was working on a Django application that needed to reach out to a third party REST API to get some data to display to the user. The external request from Django to the third party REST API needed to happen on page load so I can add the response data to the context and access it in the template. Below is an example of what a ListView with an external http request could look like using the requests library.

# views.py
import requests
from django.views.generic.list import ListView

from my_project.settings import SERVER_URL
from my_app.models import MyModel


class MyListView(ListView):
    model = MyModel

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        r = requests.get(f"{SERVER_URL}")
        context["http_data"] = r.json()["data"]
        return context

And an example of accessing the response data in the template:

<!-- templates/my_app/mymodel_list.html -->
<div>
  {% for data in http_data %}
  <div>{{ data }}</div>
  {% endfor %}
</div>

I use Django class based views for almost all of my apps, and this one is no exception. So, I figured the easiest place to make the request would be in the get_context_data method. This method is called before the view is rendered, so it’s a good candidate for me to override and include the external request logic in. It also makes sense to add the logic here because I want to add the response data to the context so I can access it in the template.

As far as I know Django does not have its own library for making HTTP requests, so I reached for the requests library for that. I installed it alongside Django in my virtual environment, but it can be installed anywhere as long as the Django app can access it.

pip install requests

It’s worth mentioning that the example above doesn’t do any error handling, and assumes each external http request will be ok. This is a dangerous assumption to make, but the example above is just a short demo to show how the request can be made without getting too deep in the weeds. It would be better if the request response was checked for errors and bad statuses. The view could be updated to display a message to the user if there was a problem with the external request.

It’s also worth mentioning that the external request will block the view from rendering until the external http request is completed. This could potentially be a bad experience for the end user, depending on how long the request takes. In most cases, the external request will be going to a third party that is controlled by someone else. It won’t be possible to reliably know how fast the response is going to come back from it.

One good way to deal with the problem of slow third party request is to put a task queue between the Django application and the third party service. This way, a response will reliably come back from the queue that indicates what the status of the external request is. Then it’s a matter of implementing a system in the Django application to check or poll the status of the task in the queue. Using Celery is a good option for implementing a task queue in Django applications.