Pixies, part 8: The Rest Service


Django Rest Framework

Once we have the data in our backend, we want to expose it to be consumed by our React frontend. Django, per se, is a traditional Web framework, it produces the html files, not json documents. There is this amazing library, called Django Rest Framework (DRF), which allows to easily add the ability to add the Rest API to the Django application. At the moment, DRF is not technically a part of Django and must be installed separately

pip install djangorestframework

Once installed, we need to enable it in the settings.py:

INSTALLED_APPS = [
    #....
    "rest_framework",
]

In order to map models to the json documents, DRF utilizes the concept of serializers. Let’s create one, In a new file pixes/photos.serializers.py enter

from rest_framework import serializers

from pixies.photos.models import Photo

class PhotoSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ["id", "url", "caption", "details"]
        model = Photo

We are saying essentially, for every Photo entity we want the json document to include id, caption and details. Notice that we excluded the created_at and updated_at fields as we are not going to use them in the frontend.

Serializer takes care of converting the model to json. We also need to add one or more views which will return the data once certain URL is provided. You could, for example, create a view which represents individual photo, or a view which represents a list of all photos. For our small application, the list view will be exactly what we are going to use. In the file pixies/photos/views.py do

from rest_framework import generics

from pixies.photos.models import Photo
from pixies.photos.serializers import PhotoSerializer

class PhotosListView(generics.ListAPIView):
    queryset = Photo.objects.all()
    serializer_class = PhotoSerializer

Observe how DRF provides the generics.ListAPIView which needs to be just configured with the serializer and the query which retrieves the data we care about. In our case, it is just a list of all photos.

The last part of setting our Rest API is to provide the way to map the particular URL to the view we just created. Recall that when we scaffolded the Django project, it created a pixies/urls.py file which is the map of all URLs our backend app is aware of. At the moment it has only an entry for the admin. We could have hook our PhotosListView right there, but it is considered a good practice to keep the urls which belong to different Django apps separately (remember, the Django project is made of apps and the photos is the app) So create a file pixies.photos.urls with the following

from django.urls import path

from .views import PhotosListView

urlpatterns = [path("", PhotosListView.as_view())]

It says essentially, as far as the photos app is concerned, always return the PhotosListView. The next step is to wire this into the central pixies.urls.py. Make it look like this:

from django.contrib import admin
# add include to imports
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    # new
    path("api/", include("pixies.photos.urls")),
]

This map says, that when Django sees the prefix admin/, it will ask built-in admin to handle it. But when it sees the prefix api, it will let the photos app to take care of it. As you remember, that always returns just the list of all photos.

All right, we are ready to try it. Make sure your Postgres container is running and run the backend:

python manage.py runserver

Navigate to the http://localhost:8000/api/ and you should see the page generated by the DRF which shows the json document with the list of our photos. If you want to see the raw json as our frontend would see, click on the select json from the menu on the GET button. Before we move on, one note - since we added custom URLs, the Django won’t generate the welcome page on the http://localhost:8000/. That is ok, we won’t be using that. admin and api are the only two endpoints we are going to need. In the next module, we are going to containerize our backend


See also