In Part 26,we used an external API to fetch some data for our movies. In this article, we will create our own API by using Django Rest Framework. By creating our own API, we can allow other computers to carry out CRUD (create, read, update or delete) operations on our database. Django Rest Framework offers several ways to create your own API. In this Post, I will cover Class Based Views and Mixins. Thanks to Class Based Views, the code we have to write becomes a lot shorter and DRY (Dont Repeat Yourself) pricinple can be carried out easily.
Make sure virtual environment is activated. Run the below command to install Django Rest Framework.
pip install djangorestframework
Add rest_framework to your INSTALLED_APPS in settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
Create a file named serializers.py in your application folder and create a serializer class for your model
from rest_framework import serializers
from .models import Movie
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = ['title', 'gender', 'description', 'publishDate', 'movieapp_score', 'numberOfViews', 'resolution']
Create these 2 urls in urls.py
path('movieapilist/', views.MovieApiList.as_view()),
path('movieapidetails/<int:pk>', views.MovieApiDetails.as_view()),
Import the followings and create 2 class based views (UserList and User Detail) in views.py
#FOR REST API
from .models import Movie
from .serializers import MovieSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class MovieApiList(APIView):
def get(self, request):
movies = Movie.objects.all()
serializer = MovieSerializer(movies, many=True)
return Response(serializer.data)
def post(self,request):
serializer = MovieSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class MovieApiDetails(APIView):
def get_object(self, pk):
try:
return Movie.objects.get(pk=pk)
except Movie.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
movie = self.get_object(pk)
serializer = MovieSerializer(movie)
return Response(serializer.data)
def put(self, request, pk, format=None):
movie = self.get_object(pk)
serializer = MovieSerializer(movie, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
movie = self.get_object(pk)
movie.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
If I browse the url http://127.0.0.1:8000/moviesapp/movieapilist/ , I get the JSON formatted data like this.
MovieApiList POST: At the bottom of this page, there is a form that we can create new objects in the database
MovieApiDetails:
If I browse the url http://127.0.0.1:8000/moviesapp/movieapidetails/3 like this, I can get the object with the id 3.
MovieApiDetails PUT:
I can update the existing movie objects like this
MovieApiDetails DELETE:
We can also delete the object from database.
USING MIXINS & GENERIC CLASS-BASED VIEWS:
We can even have less code by using Generic Class-Based Views and Mixins.
First create 2 new urls in urls.py
path('genericapilist/', views.GenericApiList.as_view()),
path('genericapidetail/<int:pk>', views.GenericApiDetail.as_view()),
Then create 2 generic views. The queryset and serializer_class names mandatory. You can not change them.
#Generic Class-Based View with Mixins
from rest_framework import mixins
from rest_framework import generics
from .serializers import MovieSerializer
class GenericApiList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class GenericApiDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)


AUTHENTICATION and PERMISSIONS:
We need some kind of authentication system to secure our API.
Basic Authentication: This authentication scheme uses HTTP Basic Authentication, signed against a user's username and password. Basic authentication is generally only appropriate for testing.
First import authentication and permission classes. Then add these 2 lines of codes in the GenericApiList and GenericApiDetail classes
from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication
from rest_framework.permissions import IsAuthenticated
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class GenericApiList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
queryset = Movie.objects.all()
serializer_class = MovieSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class GenericApiDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
queryset = Movie.objects.all()
serializer_class = MovieSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
If we try to open up api links now, we will get "Authentication credentials were not provided." message.
Token Authentication:
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
Just change the authentication_classes to "TokenAuthentication"
authentication_classes = [TokenAuthentication ]
Add authtoken in settings.py
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
Make sure you you run migrate command. (python3 manage.py migrate)
We can now create tokens for our registered users from admin panel.
We created an API key for one of our users.
You can test your API using POSTMAN.
Enter the url > Select Headers Tab > Key field should be "Authentication" > Value field should be "token yourtoken"> Click Send