Build a Blog REST API with Django REST Framework

Building a REST API with Django  and Dango Rest Framework is so super easy. In this tutorial, we’ll walk through the steps to get your first API up and running.

 

I am not going to waste your time by writing a lot of details about Django and Django Rest Framework.

Let’s start coding.

Step 1.  Create  the project directory and navigate to that directory

mkdir blogapi

cd blogpai

Step2. Create a virtual environment

python -m venv env

Step3. Activate virtual environment.

.  env/bin/activate or source env/bin/activate

Step4. Install Django and Django REST framework into the virtual environment

pip install django 

pip install djangorestframework

Step5. Create django project

django-admin startproject blogapi

Step6. Create app blogpostapi

cd blogpai

python manage.py startapp blogpostapi

Step7.  Add your app in Installed app in settings.py file and don’t forget to add rest_framework in installed app.

Application definition

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

 

Step8. Create super user.

python manage.py createsuperuser

Step9. Go to models.py file in your blogpostapi and paste the following code

#models.py in blogpostapi

Follow the  link if you want to explore more .

https://docs.djangoproject.com/en/3.1/topics/db/managers/

https://docs.djangoproject.com/en/3.1/ref/models/fields/

from django.db import models
# Create your models here.
from django.utils import timezone
from django.contrib.auth.models import User

class PublishedManager(models.Manager):
    def get_queryset(self):
    """
    The super() function in Python makes class inheritance more manageable and extensible.
    The function returns a temporary object that allows reference to a parent class by the keyword super.
    """
    return super().get_queryset().filter(status='published')




class Post(models.Model):
    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
    )

    title = models.CharField(max_length=250)
    #unique_for_date parameter to this field so that you can build URLs for posts using their publish date and slug . Django will prevent multiple posts from having the same slug for a given date.
    slug = models.SlugField(max_length=250, unique_for_date='publish')
    #https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ForeignKey.on_delete .
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    #This field shows the status of a post. You use a choices parameter, so the value of this field can only be set to one of the given choices.
    #https://docs.djangoproject.com/en/3.0/ref/models/fields/
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    objects = models.Manager() #The default manager.
    published = PublishedManager() #Our custom manager.

    class Meta:
        ordering = ('-publish',)

    def __str__(self):
        return self.title


Step10. Use the following command to migrate your model.

python manage.py makemigrations 

python manage.py migrate

Step11. Register your Post model in django admin.

Go to admin.py file in your blogpostapi and register Post Model.  This is the simplest way to add Model with django admin.

Follow the link if you want to explore more

https://docs.djangoproject.com/en/3.1/ref/contrib/admin/

from django.contrib import admin

# Register your models here.
from blogpostapi.models import Post

admin.site.register(Post)

Step12. Create an api folder in blogpostapi.

.
├── blogapi
│   ├── asgi.py
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── settings.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── wsgi.cpython-39.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── blogpostapi
│   ├── admin.py
│   ├── api
│   │   ├── __pycache__
│   │   │   ├── serializers.cpython-39.pyc
│   │   │   ├── urls.cpython-39.pyc
│   │   │   └── views.cpython-39.pyc
│   │   ├── serializers.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── 0002_auto_20210214_1223.py
│   │   ├── 0003_auto_20210214_1235.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │   ├── 0001_initial.cpython-39.pyc
│   │   ├── 0002_auto_20210214_1223.cpython-39.pyc
│   │   ├── 0003_auto_20210214_1235.cpython-39.pyc
│   │   └── __init__.cpython-39.pyc
│   ├── models.py
│   ├── __pycache__
│   │   ├── admin.cpython-39.pyc
│   │   ├── __init__.cpython-39.pyc
│   │   └── models.cpython-39.pyc
│   ├── tests.py
│   └── views.py
├── db.sqlite3
└── manage.py

Step13. Create serializers.py , urls.py and views.py under api folder and add the following code.

#serializers.py 

from rest_framework import serializers
from django.contrib.auth import get_user_model
from blogpostapi.models import Post

class PostSerializer(serializers.ModelSerializer):

    author = serializers.StringRelatedField(read_only=True,)
    status = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Post
        fields = "__all__"
#views.py 

from blogpostapi.models import Post
from blogpostapi.api.serializers import PostSerializer
from rest_framework import generics
from rest_framework import permissions


class PostList(generics.ListAPIView):
    #queryset = Post.objects.all()
    serializer_class = PostSerializer
    def get_queryset(self):
        """
        override the queryset method.
        """
        return Post.objects.filter(status='published')


class PostDetail(generics.RetrieveAPIView):
    #queryset = Post.objects.all()
    serializer_class = PostSerializer
    #permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    def get_queryset(self):
        """
       Override the queryset method.
        """
       return Post.objects.filter(status='published')

#urls.py

from django.urls import path
from blogpostapi.api.views import PostDetail, PostList
urlpatterns = [
    path('posts/', PostList.as_view(), name='posts-list'),
    path('posts/<int:pk>/', PostDetail.as_view(), name='post-detail'),
]

 

Now open urls.py file in main project folder and include blogpostapi urls.

#urls.py in blogapi 

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

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

 

 

Leave a Reply