DEV Community

Cover image for SIMPLE  REST API WITH DJANGO REST FRAMEWORK.
Habib Audu
Habib Audu

Posted on

SIMPLE REST API WITH DJANGO REST FRAMEWORK.

Hi guys! In this post am going to be taking us on how to build a simple rest Api with Django rest framework, performing all CRUD (create, read, update, delete) operations. Django rest framework is a robust toolkit for building web APIs.

A RESTful API is an application programming interface (API) that uses HTTP requests to create, Read, update and delete data.It defines a set of functions which developers can perform requests and receive responses via HTTP protocol.

GETTING STARTED
First thing first lets setup a new Django project.

install pipenv if you don't already have it

 $ pip3 install pipenv

Create a virtual environment or activate one

  $ pipenv shell

Install Django

 $ pipenv install django 

Create a Django project

 $ django-admin startproject simple_app

Create a Django app

  $ django-admin startapp rest_api 

RUN THE APPLICATION

 (simple_app) $ python manage.py runserver

The application is running at http://127.0.0.1:8000/

Alt Text

Setup Django REST Framework

 (simple_app) $ pipenv install djangorestframework

Now lets add our Django app rest_api and restframework to INSTALLED_APPS list

simple-app/settings.py

# Application definition

 INSTALLED_APPS = [
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_api.apps.RestApiConfig', # Add this line
 'rest_framework',              # Add this  line
 ]

We will be creating a sample customer API, where we can perform the various CRUD operations. Open our models file and add the following lines.

Model
rest_api/models.py

 from django.db import models
 from rest_api.helpers import LENGTH_OF_ID, generate_id


 class Customer(models.Model):

     id = models.CharField(
          max_length=LENGTH_OF_ID, primary_key=True, 
          default=generate_id,
          editable=False
          )
     name = models.CharField(max_length=100, null=False)
     product = models.CharField(max_length=100, null=False)
     is_active = models.BooleanField(default=True)
     updated_at = models.DateTimeField(auto_now=True)
     created_at = models.DateTimeField(auto_now_add=True)

Add a new file called helpers.py in our app folder

rest_api/helpers.py

 import uuid
 from django.utils.http import int_to_base36

 LENGTH_OF_ID = 12

 def generate_id() -> str:
     """Generates random string with length of `ID_LENGTH`"""
     return int_to_base36(uuid.uuid4().int)[:LENGTH_OF_ID]

helpers.py helps us generate unique ids of length 12

Now run this two commands on the terminal

 (simple_app) $ python manage.py makemigrations
 (simple_app) $ python manage.py migrate

Makemigrations is responsible for packaging up your model changes into individual migration files, so anytime a change is made on your models.py you need to run python manage.py makemigrations. Migrate is responsible for applying those changes to your database, you should also run python manage.py migrate every time you generate a new migration file.

Serialize The Customer Model

Add a new file called serializer.py in our app folder

rest_api/serializer.py

from rest_framework import serializers
from rest_api.models import Customer


class CustomerSerializer(serializers.ModelSerializer):

     class Meta:
        model = Customer
        fields = ["id", "name", 
                   "product","is_active","created_at","updated_at"]

A serializer converts data stored in the database and data you define in the models into a format which is more easily communicated via an API.
Now django models represent data stored in your database, but an API will need to transmit information in a less complex structure.
so the serializer convert your data into JSON so it can be transmitted over an API.

ViewSet
serializers translate information in both directionsreads and writes, views defines the functionsread, create, update, deletewhich will be available via the API. It has the following built-in operations.

create(): To Create an instance.
retrieve(): Retrieve/Read an instance.
update() : Update all fields of an instance.
partial_update(): Update selected fields of an instance.
destroy(): Deletes an instance.
list(): Retrieve/Read an instance.

To CREATE a customer lets populate our view open views.py in our app folder.

rest_api/views.py

from rest_framework import viewsets
from rest_framework.status import (
     HTTP_201_CREATED,
     HTTP_200_OK,
     HTTP_400_BAD_REQUEST,
     HTTP_404_NOT_FOUND,
     HTTP_204_NO_CONTENT
     )
from rest_framework.response import Response
from rest_api.models import Customer
from rest_api.serializer import CustomerSerializer

class CustomerViewSet(viewsets.ViewSet):
    '''ViewSet to add a customer'''
    serializer_class = CustomerSerializer

    def create(self, request):
        serializer = self.serializer_class(data=request.data)
        if not serializer.is_valid():
            return Response(status=HTTP_400_BAD_REQUEST)
        serializer.save()
        return Response(data=serializer.data, 
                         status=HTTP_201_CREATED)

we have imported some modules here, `viewsets` from rest_framework, which is going to serve as the `superclass` to our `CusterViewSets`,various status code from rest_framework to send appropriate status_code with our response,`Response` which actually sends the response, Customer model from models.py and our CustomerSerializer. Inside create(), we send the request data into the serializer for serialization, we call `is_valid()` to check the validity of our data, save() if its valid and return the serialized data with a status code of 200.

To GET all customers lets populate our view open views.py in our app folder, inside CustomerViewSet just after the create method add the following lines
rest_api/views.py

 def list(self, request):
    queryset = Customer.objects.filter(is_active=True)
    serializer = CustomerSerializer(queryset, many=True)
    return Response(data=serializer.data,status=HTTP_200_OK)

Here we query our Customer table/model for all instances of customer where the value of `is_active` is `True` and pass the resulting `queryset` into our CustomerSerializer for serialization, then return the serialized data and a status code of 200.

To DELETE a customer lets populate our view open views.py in our app folder, inside CustomerViewSet just after the list() method add the following lines
rest_api/views.py

 def destroy(self, request, pk):
    try:
        customer_detail = Customer.objects.get(pk=pk, is_active=True)
    except Customer.DoesNotExist:
        return Response(status=HTTP_404_NOT_FOUND)
    customer_detail.is_active = False
    customer_detail.save()
    return Response(status=HTTP_204_NO_CONTENT)

Here we try to get an instance of customer which has `pk` that was passed and has is_active as True, if thats is successful we change `is_active` to `False`, save() and return status of 204.

To PATCH a customer lets populate our view open views.py in our app folder, inside CustomerViewSet just after the destroy() method add the following lines of code.
rest_api/views.py

 def partial_update(self, request, pk):
    customer = Customer.objects.filter(pk=pk).first()
    if not customer:
        return Response(status=HTTP_404_NOT_FOUND)
    serializer = self.serializer_class(
        customer, data=request.data, partial=True)

    if serializer.is_valid():
        serializer.save()
        return Response(data=serializer.data, status=HTTP_200_OK)

Here we try to get an instance of customer with the `primary_key` that was passed `(pk)`, if thats is successful we pass the customer instance and request data into our serializer, if our serializer is valid we save() and return a response with serialized data and appropriate status code.

Next open serializer.py inside class CustomerSerializer just after class Meta add the following lines

rest_api/serializer.py

 def update(self, instance, validated_data):
    instance.name = validated_data.get("name",instance.name)
    instance.product = validated_data.get("product",instance.product)
    instance.save()
    return instance

To update we call the update() method inside the serializer class, it takes an instance of the object to update and validated data from the serializer. It update the instance save and return the instance to the view.

Now lets map to url, create another file in our django app url.py

rest_api/url.py

from django.urls import path, include
from django.conf.urls import url
from rest_api.views import (CustomerViewSet)
from rest_framework.routers import DefaultRouter

router = DefaultRouter(trailing_slash=False)
router.register(r'customer', CustomerViewSet, basename='customer')

urlpatterns = [
    url(r'', include(router.urls)),
    ]

Now register this url in our project urls, Open simple_api/urls.py, you can if you like remove all uncommented code there and add the following lines

 from django.urls import path, include

 urlpatterns = [
     path("api/v1/", include("rest_api.url")),
    ]

This just includes the url we created in our rest_api.url.py file

Start server

 (simple_app) $ python manage.py runserver

Fire up postman. url http://127.0.0.1:8000/api/v1/customer

url

Alt Text

Feel free to run GET,DELETE and PATCH.

Conclusion
I don't think you can go wrong with django restframework wink.
Thanks for Reading cheers...

Top comments (0)