In this tutorial we’ll explore Django Rest Framework. This tutorial assumes that you are using a Linux-based system, macOS or WSL and you already have Python3 with venv installed in your system. So, let’s first create a new folder by entering following command:
mkdir myapp
Now, go inside this newly created folder:
cd myapp
Then create virtual environment:
python3 -m venv .env
And then mount the virtual environment:
source .env/bin/activate
If you are on Windows, then run following command:
.\.env\Scripts\activate
Now, install Django REST Framework:
pip install djangorestframework
The above command will also install Django along with Django Rest framework. Then create the project by entering following command:
django-admin startproject project .
Next, create an app named posts:
python manage.py startapp posts
Then, amend project/settings.py as follows in order to add posts app:
INSTALLED_APPS = [
'posts',
'rest_framework',
# ...
]
Open posts/models.py and amend as follows:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.CharField(max_length=1000)
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
content = models.CharField(max_length=1000)
def __str__(self):
return self.name
Now create migration by entering:
python manage.py makemigrations posts
Then execute:
python manage.py migrate
Create serializers.py file in the posts folder and then put following code in the posts/serializers.py:
from rest_framework import serializers
from .models import Post, Comment
class PostSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Post
fields = ['title', 'body']
class CommentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Comment
fields = ['post', 'name', 'content']
Now open posts/views.py and amend it as follows:
from rest_framework import permissions, viewsets
from .serializers import PostSerializer, CommentSerializer
from .models import Post, Comment
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticated]
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
permission_classes = [permissions.IsAuthenticated]
Next, open project/urls.py and amend it as follows:
from django.contrib import admin
from django.urls import include, path
from rest_framework import routers
from posts import views
router = routers.DefaultRouter()
router.register(r'posts', views.PostViewSet)
router.register(r'comments', views.CommentViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
To register models in admin, open posts/admin.py and amend it as follows:
from django.contrib import admin
from .models import Post, Comment
admin.site.register(Post)
admin.site.register(Comment)
For pagination, open project/settings.py and insert following:
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
}
Create superuser:
python manage.py createsuperuser --username admin --email admin@domain.com
Finally run server:
python manage.py runserver
And then head to Django admin:
http://localhost:8000/admin
Now add a couple of posts and then add a couple of comments to post 1. Now, you can test posts / comments api using command line tool curl by forming command like:
curl -u admin -H 'Accept: application/json; indent=4' http://127.0.0.1:8000/posts/
Or through browser:
http://localhost:8000/posts
BONUS CODE:
Now, if we want to make a nested api call like /posts/1/comments, we need to change posts/views.py as follows:
from rest_framework import permissions, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .serializers import PostSerializer, CommentSerializer
from .models import Post, Comment
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticated]
@action(detail=True, methods=['get'])
def comments(self, request, pk=None):
post = self.get_object()
comments = post.comment_set.all()
serializer = CommentSerializer(
comments,
many=True,
context={'request': request}
)
return Response(serializer.data)
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
permission_classes = [permissions.IsAuthenticated]
The above change introduces a custom action comments within PostViewSet class. Now you can enter the following URL:
http://localhost:8000/posts/1/comments
The above nested api call will return comments related to post 1 only.