Writing APIs with DRF(Django Rest Framework)

Prajwal Kulkarni
Analytics Vidhya
Published in
6 min readJun 19, 2020

Ever since the release of Django (web framework built on Python), web developers have chosen it as one of their favorite platforms to work on and build stuff.

Flexibility and scalability are two of the major reasons for its demand and popularity.

This article mainly focuses on how to get started with writing REST APIs using DRF, and requires you to have a basic idea about python and setting up a Django project.

Let’s hop into the tutorial.

What is Django Rest Framework?

DRF(Django rest framework) is a python based toolkit for building Web APIs.

By APIs, I mean REST APIs. Almost all backend-dependent services make use of REST APIs to be consumed by the clients. So, if your project is supposed to have multiple users, you need to write efficient and sensible endpoints.

Before we get started, I’d want you to be clear about the difference between REST API and DRF.

An API(application program interface) is an architecture that allows programs to talk to each other. API is developed on a server and lets the client talk to it via URLs. The URL is called the request and the data which is sent back is called a response.

REST(Representational state transfer) is a set of rules on the API, which determines how the response should be formatted, what should be the response to different requests, and so forth.

Whereas, Django Rest Framework is a tool to build REST APIs, which otherwise could be built using other toolkits as well, depending upon the web framework being used.

Enough of the introduction, let’s get started right away…

Installation

First, we need to install the DRF library. Make sure your virtual environment is activated.

Command to install DRF:

pip install djangorestframework

Add, ‘rest_framework’ and ‘rest_framework.authtoken’ to INSTALLED_APPS in settings.py.

INSTALLED_APPS = [...'rest_framework','rest_framework.authtoken',]

Now, the DRF is ready to be used.

Let’s start writing our API.

When writing an API, it is important to note 3 things

  1. Endpoint
  2. Response content
  3. Permitted request type(s).

An endpoint is a URL where a request can be made.

Response content determines the response format.

Permitted request constrains the endpoint to one or more request methods.

The primary need of endpoint is to perform CRUD operation on a database, this means it’s mandatory to have a database or what is referred to as a model in Django, where data could be stored and manipulated using endpoints.

For this project, let’s have a simple model which stores names of users.

In models.py

from django.db import modelsclass UserNames(models.Model):
user_name = models.CharField(max_length=264)

def __str__(self):
return self.user_name

The above code represents a model with “user_name” field.

Register the model in admin.py and run migrations.

admin.py

from <your-app-name>.models import UserNamesadmin.site.register(UserNames)

Then, run the following commands in your terminal(with virtual environment enabled).

python manage.py makemigrations
python manage.py migrate

This would create the ‘UserName’ model and register it on the admin panel.

Empty User name model

If you successfully created the model, it should look something like the one shown above.

Let’s add some dummy data by clicking on “ADD USERNAMES” present in the top right corner.

Now, we’ve a model with some data in it.

In a regular simple project, we associate the model to a form or directly feed values from the views. But, for an API, we make use of something called as serializers.

Serializers convert model instances to Python dictionaries. These dictionaries are further used to render API in formats like JSON or XML.

Create a new file in your Django app as ‘serializers.py’

Add the following code in serializers.py

serializers.py

from <your-app-name>.models import UserNamesfrom rest_framework import serializersclass UserNamesSerializers(serializers.ModelSerializer):
class Meta:
model = UserNames
fields = "__all__"

The above code is self-explanatory. We’re creating a serializer “UserNamesSerializer” which is linked to the model “UserNames”, i.e, the API associated with this serializer renders information available in the “UserNames” model.

Additionally, the field variable decides which column’s data is to be displayed.

“__all__” means to include all the fields. We might instead use a tuple as well if we needed to display certain information only. For instance, a user model (username, email, password), displaying password would not be a good idea.

In such a case, we could replace “__all__” with a tuple having only the required fields.

fields = (name,email)

or

fields = exclude(password) 
#Includes all the other fields except password

The serializer is ready, we shall now connect this serializer to a view set.

A view set binds a serializer with other rules such as permissions and querying.

In views.py, add the following

from rest_framework import viewsets
from rest_framework import permissions,generics
from app.serializers import UserNamesSerializers
from rest_framework.permissions import IsAuthenticated
from <your-app-name>.models import UserNames
class UserNameViewSet(viewsets.ModelViewSet):
# this fetches all the rows of data in the UserNames table
# customize it as required
queryset = UserNames.objects.all()
serializer_class = UserNamesSerializers

Note that, we’re using a class-based view, the same could be achieved using functions as well.

The final step is to establish a relation between a request endpoint and the view-set.

Go to urls.py, and configure URLs with the respective view-sets.

from <your-app-name> import views
from django.contrib import admin
from rest_framework import routers
router = routers.DefaultRouter()router.register(r'demo/users/',views.UserNameViewSet)admin.autodiscover()

Routers are similar to ‘url_patterns’, difference being, ‘url_patterns’ deal with regular views and routers deal with API based views.

The ‘demo/users/’ is our endpoint here, you could replace it with anything you like.

Save changes, fire up your terminal and start the server.

Then go to the created endpoint (‘demo/users/’) in this case, and you should see a list of user names that you had added after creating the model.

Endpoint displaying usernames

Alternatively, a cURL request could be made from the terminal, and it should fetch the same information too.

Sometimes, it’d require us to have some partially sensitive information on API, which we’d like to be accessed by, say, authenticated users only.

Here, we can restrict un-authenticated users from accessing the information,

by literally adding a single line of code.

class UserNameViewSet(viewsets.ModelViewSet):
# this fetches all the rows of data in the UserNames table
# customize it as required
permission_class = (IsAuthenticated,)
queryset = UserNames.objects.all()
serializer_class = UserNamesSerializers

Now the API is protected from unauthorized access.

Hence, this endpoint can now be only accessed by sending a valid token in the request.

Insert data using API

Till now, we saw how to create a basic API and extract information from it.

Now let us look at how can we add information into the API.

This is fairly simple and requires fewer changes.

In ‘views.py’, make the following changes in the view-set.

def get_permissions(self):if self.action == "create":self.permission_classes = settings.PERMISSIONS.user_createelif self.action == "list":self.permission_classes = settings.PERMISSIONS.user_listreturn super().get_permissions()

After saving changes and reloading the URL, we can observe an input box through which we can add values into the model.

Notice, the “if-elif” block, which has options to create(add) and list(display) usernames from/to the model.

By default, from now the information will be shown only to authorized users, that’s the reason why super().get_permissions() is returned.

Let’s see if it works or not, by adding a value from the endpoint.

POST request in API endpoint

As we can see above, I posted the string “added from input field” into the model, and I got a response code of 201, which implies that the value has been successfully added into the database.

We can verify the same from the admin panel.

The circled string matches with the one I posted from the endpoint, therefore it is verified that the POST request is working as expected.

Congratulations, you successfully wrote your first API. :) :)

Found this article informative?

If you found this article helpful, feel free to give me some claps and connect with me on Instagram.

If you have any questions, feel free to drop them in the comments!

--

--