Create REST APIs in Django REST Framework

REST APIs can be created elegantly using python’s djangorestframework module in a Django project.
Django Rest Framework module provides simple and sophisticated ways of creating APIs. Django Rest Framework is
also known as DRF, we will use this acronym to save space and time.

 

Following prerequisites required

1. Install “djangorestframework” module in your django project.
`pip install djangorestframework`

2. Add “rest_framework” to INSTALLED_APPS list in settings.py

3. Run the migrations
`python manage.py makemigrations`
`python manage.py migrate`

 

Now setup is completed, lets create simple API which returns sample data in JSON format.

We will go from simple to complex, We will create simple API which gives you JSON output, just a message “Hello
World”. Once completed, you check output in your browser at http://localhost:8000/hello-world-api/

Fastest (but not dirty) way
The shortest and fastest way to is to create a python function and write all logic there.

In views.py file add following


from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view()
def hello_world_api(request):
return Response({"message": "Hello, world!"})

Add link to urls.py file


from django.contrib import admin
from django.urls import path
from drf_api.views import hello_world_api
urlpatterns = [
path('hello-world-api/', hello_world_api), # Add this to add API to project urls
path('admin/', admin.site.urls),
]

Somewhat more elegant way.
We can create python class which extends APIView.


from rest_framework.views import APIView
from rest_framework.response import Response
class HelloWorldAPIView(APIView):
def get(self, request):
return Response({'message': 'Hello, World!'})

To use above as API you will need to connect it to URL to do that,
in project’s `urls.py` file add following entry in `urlpatterns` list.


from django.contrib import admin
from django.urls import path
from drf_api.views import HelloWorldAPIView
urlpatterns = [
path('hello-world-api/', HelloWorldAPIView.as_view()),
path('admin/', admin.site.urls),
]

 

Specialized Views, don’t get stuck into “Hello World” only

There are classes in DRF which you can extend to create APIs for specialized cases, like listing database
table entries, creating/modifying/deleting database table record. You can do things close to zen of
REST APIs.

You can create REST API around Django model which is database table under the hood. Almost in all cases model corresponds to table in database. Here you can think of this model as “resource” in REST terminology, and on this resource you can create apis to honor REST verbs like GET, POST, PUT, DELETE etc.

DRF provides lot of model based views which gives you built in APIs to manage model. To use model based APIs you will need model


from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=100)
director = models.CharField(max_length=100)

and model serializer


from rest_framework import serializers
from .models import Movie
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'

Lets start with ListAPIView, Classes you can extend are

ListAPIView

This gives you GET API to list model items.


from rest_framework.generics import ListAPIView
from .models import Movie
from .serializers import MovieSerializer
class MovieListAPIView(ListAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer

You will need to add URL entry in project URLs,


from django.contrib import admin
from django.urls import path
from drf_api.movie_list_api_view import MovieListAPIView
urlpatterns = [
path('movie-list/', MovieListAPIView.as_view()),
path('admin/', admin.site.urls),
]

You can check http://localhost:8000/movie-list/, Response for API will be,


[
{
"id": 1,
"title": "The Shawshank Redemption",
"director": "Frank Darabont"
},
{
"id": 2,
"title": "The Godfather",
"director": "Francis Ford Coppola"
},
{
"id": 3,
"title": "The Dark Knight",
"director": "Christopher Nolan"
}
]

We will not list code samples for rest of the views here, but I have added them on github project

 

CreateAPIView

This POST api to create model object. e.g. curl -d “{\”title\”: \”New Movie 2\”, \”director\”:\”New Director 2\”}” -H “Content-Type: application/json”
-X POST http://localhost:8000/movie-create-api/ This will create new model objects. It supports POST method only.

 

RetrieveAPIView  

This gives you GET API(accepts pk of model as param) to give particular model item. e.g. http://localhost:8000/movie-retrieve-api/1/ , This will fetch and display movie record of id equal to 1. If you give invalid id, API will return empty response with 404 status.

 

DestroyAPIView

This gives you DELETE API(accepts pk of model as param) to delete particular model item, e.g. curl -X DELETE http://localhost:8000/movie-destroy-api/3/, This will delete movie with id 3. It accepts DELETE as http request method.

 

UpdateAPIView

This gives you PUT API (accepts pk of model as param) to update particular model item. It accepts PUT and PATCH as http request methods. For PUT http method it needs you send whole object to update.

e.g. curl -d “{\”title\”: \”The Shawshank Redemption 2\”, \”director\”:\”Frank Darabont I\”}” -H “Content-Type:
application/json” -X PUT http://localhost:8000/movie-update-api/1/

For PATCH http method you can send individual attribute.

e.g. curl -d “{\”title\”: \”The Shawshank Redemption 3\”}” -H “Content-Type: application/json” -X PATCH http://l
ocalhost:8000/movie-update-api/1/

 

RetrieveUpdateAPIView

This is mix of retrieve and update. GET request along with id will retrieve the model record curl -H “Content-Type: application/json” -X GET http://localhost:8000/movie-retrieve-destroy-api/1/ and PUT and PATCH requests will update the same model record.

 

ListCreateAPIView

This is mix of list and create. GET request to API will return list of model items curl -H “Content-Type: application/json” -X GET http://localhost:8000/movie-list-create-api/, and POST request to API will try to create new model item curl -d “{\”title\”: \”New Movie\”, \”director\”:\”New Director\”}” -H “Content-Type: application/json” -X
POST http://localhost:8000/movie-list-create-api/
.

 

RetrieveDestroyAPIView

This is mix of retrieve and delete. GET request to API along with id will retrieve model record curl -H “Content-Type: application/json” -X GET http://localhost:8000/movie-retrieve-destroy-api/4/
and DELETE request will delete the corresponding model record curl -H “Content-Type: application/json” -X DELETE http://localhost:8000/movie-retrieve-destroy-api/4/.

 

RetrieveUpdateDestroyAPIView

This is mix of retrieve, update and delete. GET request curl -H “Content-Type: application/json” -X GET http://localhost:8000/movie-retrieve-update-destroy-api/5/ will return model with given id. PUT,PATCH will update model object as whole and partially respectively. DELETE request will delete the model object of given id.

 

Viewsets

You can group related views in single class aka viewsets in DRF.

ViewSet

This class by default does not provide any actions, but you can define list, create, retrieve, update, partial_update and destroy methods to use it in REST convention on URL with methods GET, POST, GET, PUT, PATCH and DELETE respectively.


from rest_framework.viewsets import ViewSet, ModelViewSet
from .models import Movie
from .serializers import MovieSerializer
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
class MovieViewSet(ViewSet):
def list(self, request):
queryset = Movie.objects.all()
serializer = MovieSerializer(queryset, many=True)
return Response(serializer.data)
def create(self, request):
serializer = MovieSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Movie.objects.all()
movie = get_object_or_404(queryset, pk=pk)
serializer = MovieSerializer(movie)
return Response(serializer.data)
def update(self, request, pk=None):
queryset = Movie.objects.all()
movie = get_object_or_404(queryset, pk=pk)
serializer = MovieSerializer(movie, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def partial_update(self, request, pk=None):
queryset = Movie.objects.all()
movie = get_object_or_404(queryset, pk=pk)
serializer = MovieSerializer(movie, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def destroy(self, request, pk=None):
queryset = Movie.objects.all()
movie = get_object_or_404(queryset, pk=pk)
movie.delete()
return Response({})

In project urls file you can add link as following,


from rest_framework.routers import DefaultRouter
from drf_api.movie_viewset_api import MovieViewSet
router = DefaultRouter()
router.register(r'movies-viewset', MovieViewSet, basename='movies-viewset')
urlpatterns = router.urls

 

GenericViewSet

This gives you class where get_object and get_queryset methods are given, it does not provide any action by default If you want to use it you will need to extend one of the mixins, like CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin and DestroyModelMixin these will give you API to create, list, retrieve, update and delete model entries respectively. Using GenericViewSet and mixins you can have actions which suits your need.

 

ModelViewSet

This is mix of list, create, retrieve, update, partial update, delete views for model.

 

ReadOnlyModelViewSet

This is mix of list, retrieve actions for model. It does not involve any action which will update model entry, hence good for read only API endpoint for your model.

 

As there are lot of options available, this may be confusing sometime which one to pick. May be this can help to choose,

Do you have a single model class which can be referred as “resource” in REST way
Yes – Use specialized model based views i.e. ModelViewSet, ReadOnlyModelViewSet.
No – Use APIView and customized it to your need.

If you have multiple model class manipulations or using raw queries, but still want to create API in REST way, Use ViewSet and implement the REST methods required.

If you have use case where model is not involved or it is not core of the functionality e.g. You are uploading file processing it and returning result on the fly, you can use APIView.

 

What next?
Apart from view functions, classes there are serializers, permission classes you will need to know to make
maximum use of DRF toolset.

 

I hope this will help you to create APIs(REST) for your application. It is very simple and reliable
way, once you grok it, you will need to look back to create APIs in Django. This blog lists general
cases, there can be other specialized or complex cases where you might need to do more, but basics will
remain same. You can start your API with this basic knowledge and then extend it further to match the
requirement. If you want to know more about how particular API case can be addressed you can add comment here, I will try to get back to you.

Till then, happy coding 🙂

Leave a comment