Creating a Score API with Django: a Step by Step Guide

In this post, we are going to use Django to create a score API where we will store a gamer ID and the top score that they achieved in a game. In the past, I have used Node.js for this. However, I prefer Python, leading to Django.

If you want a quick overview of REST, see our previous post.

Initialize a Django Project

If you have not already, install Django:

pip install django

Create Django Project

Next, we will create a project called harlepengren using django-admin:

django-admin startproject harlepengren

Django-admin is a command line utility that makes administrative tasks easy. In this line, we are asking the utility to create a project called harlepengren. Note, you do not need to create this in your web server root (you don’t even need a web server running to play with Django, because Django comes with its own development web server).

You should now have a directory called harlepengren. If you go into the directory, you will see a file called manage.py, which we will use to run the project, and another folder called harlepengren that contains our top level settings (both settings.py and urls.py).

Test Run

We can test that this project runs by typing the following in the harlepengren folder with manage.py:

python manage.py runserver

Now, we can go to the web server (e.g., on local host http://localhost:8000). If it is working, you should see this image.

As a quick side note, I am remotely developing on a Raspberry Pi, so I need to edit the settings.py to add ‘raspberrypi.local’ to the allowed hosts, and I will run the server using the following:

python manage.py runserver 0.0.0.0:8000

Install Django Rest Framework

pip install djangorestframework

Edit harlepengren/harlepengren/settings.py to add rest_framework to installed apps.

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
]

Create API Application

Next, we will create an API application. An application in Django is a unit of functionality. A Django project can have multiple applications. Each app is a Python package.

To create an app, type:

python manage.py startapp api

This will create a folder call api within our root folder (harlepengren). Within this folder, it creates an __init__.py file that tells Python this is a package. In addition, it creates admin.py, apps.py, models.py, tests.py, and views.py. These are the core components of the application.

We need to add this app to the list of installed apps in harlepengren/settings.py (‘api.apps.ApiConfig’)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'api.apps.ApiConfig',
]

Create the URLs

We need to set up both the project URL as well as the application URL. When the web server receives a request, it starts with the project URL (currently in the folder harlepengren/harlepengren/). We add the following:

from django.urls import include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')),
]

The api/ line will send the request to our api application. Within the api folder, we need to create urls.py and add the following:

from django.urls import path
from . import views

urlpatterns = [
  path("", views.index, name="index"),
]

This is temporary. We will update this later once we have the API structure in place.

Add a Default View

Next, we will add a default view. In api/views.py, add the following:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("hello")

This is not necessary for our API, but useful for testing. We can test by typing the following in the root harlepengren folder:

python manage.py runserver

In a browser, simply type:

http://localhost:8000/api/

You should see a simple screen with just:

hello

Building the Model

The next step is building the model. This is essentially the database that will store our username and score information.

Choosing a Database

In the initial setup, Django created an sqlite database in the root harlepengren folder named db.sqlite3. For our purposes, we are going to use that database. However, you can use other databases if you prefer.

Migrate to the Database

When you run the server, you may have noticed a warning such as the following:

This is related to the database, and we will fix this as part of the next step. This warning just tells us that we have model changes that have not been propagated into the database. This is called migration. We will do this every time we make a model change. Migrating is really easy, and the warning tells you what to type:

python manage.py migrate

Create a User Model

The first model that we want to create is a user model. This model will just store a username for now. In the future, it could store other information about the user (e.g., email address, preferences).

To create the model, we will add the following class to harlepengren/api/models.py.

class User(models.Model):
        username = models.CharField(max_length=200)

Next, we will add a class for score that has a primary key based on the username.

class Score(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        score = models.IntegerField(default=0)

The ForeignKey method simply establishes a many to one relationship with our User table. The on_delete parameter tells the database to delete any related records in Score if the User is deleted.

Similar to the previous step, we need to migrate the changes to the database. In the root harlepengren, type:

python manage.py makemigrations api

If it runs successfully, you should see the following:

Creating the REST API

Now that we have the model, we need to set up the API. There are three steps:

  1. Serialize the model (i.e., convert to JSON/XML)
  2. Create a view to render the data
  3. Update the URLs to point to the view

Create Serializers

Serializers help to transform data from Python data structures into something that can be sent through the API (e.g., we will use JSON). In our api folder, we will create a new file called serializers.py.

from rest_framework import serializers
from .models import Score, User

class ScoreSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Score
        fields = ['user','score']

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ['username']

Create the View

Next, we are going to replace api/views.py to the following:

from rest_framework import viewsets
from .serializers import ScoreSerializer, UserSerializer
from .models import Score, User

class ScoreViewSet(viewsets.ModelViewSet):
        queryset = Score.objects.all()
        serializer_class = ScoreSerializer

class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserSerializer

We use the ModelViewSet class from Django REST framework. We provide the viewset with our query as well as our serializer.

Update the URL

We will update api/urls.py with the following:

from django.urls import include, path
from rest_framework import routers
from .views import *

router = routers.DefaultRouter()

router.register(r'score', ScoreViewSet)
router.register(r'user', UserViewSet)

urlpatterns = router.urls

We create a default router. We use the default router to register both of our viewsets. Finally, we add for our viewset and add that to the patterns.

Adding Some Data

Now that we have the API in place, let’s add some data.

Create Admin

First, we will create an admin view:

python manage.py createsuperuser

Next, we need to show our model in admin. Add the following code to api/admin.py

from django.contrib import admin
from .models import Score, User

class UserAdmin(admin.ModelAdmin):
        list_display = ['username']

class ScoreAdmin(admin.ModelAdmin):
        list_display = ['user','score']

admin.site.register(User, UserAdmin)
admin.site.register(Score, ScoreAdmin)

Now run the server and go to http://localhost:8000/admin/. You should see the following screen:

Add Data

Through either the admin screen or the django shell (python manage.py shell) add some data. In the shell, we can type the following:

from api.models import Score, User

user = User(username=”test”)
user.save()

score = Score(user=user, score=56)
score.save()

Now, if we run our server, and go to http://localhost:8000/api/score/, we should see the following:

Note that you can also add data through the API page.

Conclusion

This post provides an introduction to using the Django framework to create a REST API. Although, I am not completely convinced that this is a full replacement for something like Node.js. I definitely prefer coding in Python over Javascript. In addition, since it includes its own lightweight web server, development was incredibly easy.