Making a Simple REST API Using Django REST Framework

📅 August 11, 2019 • 🕣 6 min read

blog8

Image Source django-rest-framework.org

Originally published at iC0DE

Introduction

Django is a great framework for creating Web Apps but with necessity of Web Apps comes necessity of RESTful APIs. Django REST Framework gives us a great amount of flexibility to create powerful APIs using Django.

Let’s Make a Movie API

SETUP

Let’s create a virtual environment first:

virtualenv -p python3 api && cd api && source bin/activate

Now install the django and django-rest-framework Python packages.

pip install django django-rest-framework

You can run pip freeze to see you have following packages installed.

Django==2.2.3
django-rest-framework==0.1.0
djangorestframework==3.9.4
pytz==2019.1
sqlparse==0.3.0

CREATE A PROJECT

Now let’s create a Django Project (Movie API) by running the command below.

django-admin startproject movieapi

If you will see Django creates these files for you automatically.

Now let’s see if everything is working by running the command below.

python manage.py migrate

If everything goes well you will see the following output in your terminal.

Django provides us with a built-in server for testing our applications.Run the server using

python manage.py runserver

Now open the http://127.0.0.1:8000/ in your browser to see the following Django’s welcome page.

CREATING AN APP

Now we will create a Django App (yes! I know it’s confusing sometimes but in Django terminology apps are separate entities in a Web App take it as a subproject inside your main Web App for e.g login/profile etc).

Run the following command to create an app in Django.

django-admin startapp api

You will see a new folder, API is created with a bunch of other files.

Now for the app API to work we first have to add it to the INSTALLED _APPS list in settings.py file.

We will now create a database / tables for our movies and actors in models.py file.

from django.db import models

class actor(models.Model):
   name = models.CharField(max_length = 100)

   class Meta:
       verbose_name_plural = "Actors"

   def __str__(self):
      return self.name

class category(models.Model):
    name = models.CharField(max_length = 100)

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        return self.name

class movie(models.Model):
    title = models.CharField(max_length = 300)
    actors = models.ManyToManyField(actor)
    categories = models.ManyToManyField(category)

    class Meta:
        verbose_name_plural = "Movies"

    def __str__(self):
        return self.title

Once you create your models register them in the admin.py file so that we can access them from the admin panel (will talk about it in a minute). Go to admin.py file and add the following code.

from django.contrib import admin
from .models import category, movie, actor
# Register your models here.

admin.site.register(movie)
admin.site.register(actor)
admin.site.register(category)

Now run the following command from the terminal

python manage.py makemigrations

This will create a migration file (named 0001_initial.py) inside the migration folder. It contains some information used by Django through which it creates the database tables for us (normally you would have to use SQL to create tables but Django does everything for us).

After this migrate the tables.

python manage.py migrate

This will actually create tables for you in the database.

Now run the following command.

python manage.py createsuperuser

It creates a Django admin user (just like a WordPress C-Panel admin) through which we will be able to see our tables and their data.

Now open the URL http://127.0.0.1:8000/admin/ in your browser.

Add your login credentials and you can see indeed that our models are present in the panel and you can add new movies, actors and categories through this interface (make sure you add some because we will need them in future to test our API).

Now as we know that data from or to an API is exchanged using some formats like JSON, XML etc. We will add this functionality in our API.

Go ahead & create serializers.py file inside the API folder and add the following code.

from rest_framework import serializers
from . models import actor, movie

class actorSerializer(serializers.ModelSerializer):

    class Meta:
        model = actor
        fields = ('__all__')

class movieSerializer(serializers.ModelSerializer):
    actors = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='name'
    )
    categories = serializers.SlugRelatedField(
        many=True,
        read_only=True,
        slug_field='name'
    )

    class Meta:
        model = movie
        fields = ('__all__')

SETTING UP ENDPOINTS

Now we will create out API Endpoints though which we will request our data, create a new file urls.py inside the API folder and add the following code.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
    path('movies/', views.movies),
    path('actors/', views.actors),
]

We have defined 3 URLs here :

  1. http://127.0.0.1:8000/api/ – Home Page for API
  2. http://127.0.0.1:8000/api/movies/ – return all movies in the database.
  3. http://127.0.0.1:8000/api/actors/ – return all actors in the database.

Make sure you add the api/urls.py inside the movieapi/urls.py. Add the following code inside the movieapi/urls.py file.

from django.contrib import admin
from django.urls import path, include

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

Now as you can see in the urls.py we were importing some functions from views.py file.

We will now define these functions which will handle the logic for our API.

from django.http import HttpResponse
from rest_framework.renderers import JSONRenderer
from rest_framework.decorators import api_view
from . models import movie, actor
from .serializers import movieSerializer, actorSerializer

# Just wraps a simple HTTP Response to a JSON Response
class JSONResponse(HttpResponse):
    def __init__(self, data, **kwargs):
        content = JSONRenderer().render(data)
        kwargs['content_type'] = 'application/json'
        super(JSONResponse, self).__init__(content,**kwargs)

def index(request):
    return HttpResponse("<h3>Welcome to Movie API v1.0</h3>")

@api_view(['GET'])
def movies(request):
    movies = movie.objects.all()
    serializer = movieSerializer(movies, many=True)
    return JSONResponse(serializer.data)

@api_view(['GET'])
def actors(request):
    actors = actor.objects.all()
    serializer = actorSerializer(actors, many=True)
    return JSONResponse(serializer.data)

As you can see we have defined 3 functions which handle our API Endpoints:

  • The function named index() handles the root of our API, it just returns an HTTP response Welcome to Movie API v1.0.
  • In the movies() function we are querying all the movie objects from the database and applying the serializer to it which we made earlier. The same stuff is happening in the actor function as well.
  • @api_view is a python decorator which is used here to specify that only GET request should invoke this method.
  • The class JSONResponse is just used to wrap the database objects into a JSON format.

Result

Now if you will head over to http://127.0.0.1:8000/api/movies/ in your browser ,you will see that our API is indeed working and returning data in JSON format.

result