How to create a REST API in Django step by step (with Django REST Framework)
Content Index
- Introduction to Django and Rest APIs
- What is a Rest API and why use Django to build it?
- Advantages of Django Rest Framework (DRF)
- The main concepts of Django and the REST framework are:
- Components to create a Rest API in DRF
- Initial development environment configuration
- Installation of Django and Django Rest Framework
- Basic project configuration
- Models and Serializers: defining the data structure
- Serialization with ModelSerializer
- Creating views and ViewSets in Django Rest Framework
- Routing and API testing
- Authentication token in the Rest API using Django Rest Framework
- Points to consider
- Protecting a Rest API
- Creating the function to generate Authentication Tokens and verify credentials (login)
- Explanation of the previous function
- Testing authentication in Postman
- Protection of ModelViewSet
Django is one of those frameworks that's been on the market for a long time and is being used more every day along with the Python ecosystem: the creation of Rest APIs, which, as we've seen in several tutorials, videos, and my courses, are easily scalable, flexible, and all of this is thanks to the great modularity of the Python ecosystem, which is, of course, also inherited by Django.
Building a Rest API in Django is one of the most common tasks today, especially if you want to connect your backend with web or mobile applications in Flutter, React, Android, or iOS. Django, along with Django Rest Framework (DRF), offers an elegant, modular, and secure way to create scalable APIs without complications.
A Rest API is a fundamental component in any application today that offers us a simple, organized, and customizable mechanism to share data or functionality through other applications; it even allows us to add layers of security with relative ease if you use a framework, package, or something similar; in Django, using Django Rest Framework, this is no exception and allows us to create very personalized Rest APIs through this package for Django using classes or methods that we can customize.
So, again I repeat, there are many ways to create Rest resources using Django Rest Framework (DRF), and in this post, we are going to see the simplest, most generated, and most direct approach to learning how to take the first steps with DRF.
In my experience, after several courses and real projects, I can say that DRF greatly facilitates the work, especially when you understand its structure well: models, serializers, views, routes, and authentication.
Introduction to Django and Rest APIs
What is a Rest API and why use Django to build it?
A Rest API (Representational State Transfer) is a standard way for applications to communicate with each other through HTTP requests. Simply put, it's the "door" through which an external app can access your system's data.
Django is perfect for building APIs because it combines a powerful ORM (for handling databases without writing SQL) with a mature ecosystem and a huge community. If you already know Django, making the leap to Django Rest Framework is completely natural.
Although Rest APIs are NOT a standard, they are a measure that has been adopted by multiple frameworks to build this type of system whose main purpose is to connect with other systems or applications, as I mentioned before; so, for example, having an app in Django, we can connect it with apps created in Flutter, Android, iOS, React or anything else similar... which is excellent since with a single backend we can create multiple applications that consume this Django app.
A real-world example is an online shopping app, which is an app with a central repository created (for example) in Django and then you can create the apps for the client, either for mobile and/or browsers using (for example) the technologies indicated above...
Advantages of Django Rest Framework (DRF)
- Automatic serialization of models to JSON.
- Very flexible permission control and authentication.
- System of generic views and ViewSets that avoids duplicating code.
- Direct integration with tools like Postman or Swagger.
In my case, I have used DRF to create APIs that connect with frontends made in Flutter and React, leveraging a single stable and maintainable backend.
The main concepts of Django and the REST framework are:
Model classes provide an Object Relational Map (ORM) for the established database. A model maps to a table in the database. You can query databases without writing a single line of SQL. With models, it is easy to define tables and relationships between them.
Views are in charge of the request process. They work as controllers in the MVC; let's remember that Django uses MTV. You can implement them in many ways, such as functions or classes.
Serializer classes provide control over data types and request and response structures.
Templates are files with static and dynamic content. They are made up of static code and other elements that depend on the context, although this is not relevant in a Rest type app.
These are some of the best practices to follow when using Django for development:
Configuration structure: anyone new to development can easily create an application with ease using the Django framework. It is vital to create a structure that is easy to maintain and reuse when necessary. Whenever you use Django, generate a settings.py file that contains all the details related to the project or your work environment so that you do not make any changes to the main configuration file and generate new files for different environments.
One project, several applications in Django: there can be many applications in a single Django project. An application is a collection of related functions and model sets. It is a good practice to maintain order and define locations for standard functions. There is an application called api, through which the routing of the other applications in the main application folder can be defined.
ViewSet: is the most important component for viewing Rest APIs in Django models. Regular views in Django act as a controller for HTTP requests; view sets give you options like creating or listing. The best feature of view sets is that they make the code consistent and repetition can be avoided; therefore, with this component, we can specify the structure and which models they are going to work with.
Generic Views: the Django framework has a feature called generic views that facilitates functions and tasks related to models. Some of the functions include retrieving data, creating, and destroying lists. The only thing you have to do is define the class view as a child of the generic view.
Customize functions: the generic views provided in the Django documentation list a variety of functions such as ListAPIView, CreateAPIView, RetreiveAPIVIew, RetrieveDestroyAPIView. But if you are looking to customize the views, you can redefine get, post, put, delete, and other methods. You can also use mixins to redefine specific methods and functions like create, update, destroy, and others.
Components to create a Rest API in DRF
In DRF there are 3 main components to create any type of Rest resource:
- The serialization classes, which allow us to indicate the data set we are going to work with.
- The classes or methods with the Rest resources, which use the serializers to map the responses of the Rest resources that we create at this point.
- Routing, like any http component in Django, we have to create a path component.
And we can manage all of this using classes, properties, and functions in DRF.
Initial development environment configuration
Prerequisites
Before you begin, make sure you have Python 3.10+, pip, and a virtual environment installed. From the terminal:
$ python -m venv env
source env/bin/activate # o env\Scripts\activate en WindowsInstallation of Django and Django Rest Framework
$ pip install django djangorestframeworkThen, create a new project and a main app:
$ django-admin startproject myproject
$ cd myproject
$ python manage.py startapp apiBasic project configuration
In your settings.py file, add the necessary applications:
INSTALLED_APPS = [
...
'rest_framework',
'api',
]Maintaining one settings.py file per environment (development, testing, and production) prevents many errors when deploying. This way you can customize variables without touching the main file.
Models and Serializers: defining the data structure
Creating the base model
As an example, let's define a category table:
from django.db import models
class Category(models.Model):
title = models.CharField(max_length=255)
url_clean = models.CharField(max_length=255)
def __str__(self):
return self.titleSerialization with ModelSerializer
In serializers.py:
from rest_framework import serializers
from .models import Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'The serializer is responsible for converting Django objects into JSON format and vice versa. Thanks to Django's ORM, you can query without writing a single line of SQL.
Creating views and ViewSets in Django Rest Framework
Difference between APIView, GenericView and ViewSet
- APIView: total control, more code.
- GenericView: preconfigured views (list, create, delete).
- ViewSet: groups CRUD actions into a single class.
If your intention is to create a CRUD-type Rest API, there is already a class in DRF that you can inherit and it will be created automatically thanks to the two attributes we define, the queryset, to define the data pool, and the serializer_class to define the serializer class; all of this we will do in a file called viewsets.py:
from rest_framework import viewsets
from .models import Category
from .serializers import CategorySerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializerThe first class we have to define would be `serializers.py`, which allows us to define the serialization of our classes. This is useful for indicating which fields we are going to work with, for example, all of them:
from rest_framework import serializers
from .models import Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'Routing and API testing
Configuring routes with routers.SimpleRouter().
With our two resources created, the next thing we need is route management; for that:
from rest_framework import routers
from .viewsets import CategoryViewSet
router = routers.SimpleRouter()
router.register('category', CategoryViewSet)
urlpatterns = router.urlsThen, in our main file for the routes:
path('api/', include('restful.urls')),Testing endpoints with Postman or cURL
With the server running:
$ python manage.py runserverVisit http://localhost:8000/category/ or test with Postman.
Personally, I always test each endpoint in Postman before deploying to ensure that permissions and responses work as I expect.
Authentication token in the Rest API using Django Rest Framework
Protecting a Rest API like the one built previously, whether it is of the CRUD type or any other, so that it can only be accessed through some mechanism is a common feature today, and a widely used mechanism is through Tokens, Authentication Tokens, and we can do this easily in Django Rest Framework without much complication.
Token authentication is a widely used scheme in web applications in which we define our Rest API to protect certain resources or even the entire Rest API; we can easily configure all of this in a Rest API created with Django Rest Framework, which is what we are going to do in this post.
Points to consider
To create our Rest API with authentication token protection, we can do it natively using Django Rest Framework. For this, we have to define a couple of configurations in our settings file, specifically in the `REST_FRAMEWORK` key or key, which is the one we use to handle this type of configuration at all levels.
Protecting a Rest API
The configuration we are going to make would be to apply globally in a Rest type class; as you can see, when working with DRF we have many ways to do the same thing and here we simply offer you one version. You simply have to indicate in your Django project configuration file, called `settings.py`, and add the following configuration:
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':[
'rest_framework.permissions.IsAuthenticated'
],
'DEFAULT_AUTHENTICATION_CLASSES':[
'rest_framework.authentication.TokenAuthentication'
]
}You must also add the tokens app:
INSTALLED_APPS += ['rest_framework.authtoken']Run migrations:
$ python manage.py migrate authtokenCreating the function to generate Authentication Tokens and verify credentials (login)
Now, the next thing we have to do would be to create the function that our user would use to generate the token. This method or function will be a custom Rest resource for us that will allow us to generate said token using the `get_or_create` function of the Token model that we import for free from our DRF.
Now, we generate said token once the user's credentials have been verified against the one we have in the User model and in the database; so, finally:
from rest_framework.decorators import api_view
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from django.contrib.auth.models import User
from django.contrib.auth.hashers import check_password
@api_view(['POST'])
def login(request):
username = request.POST.get('username')
password = request.POST.get('password')
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return Response("Usuario inválido")
if not check_password(password, user.password):
return Response("Contraseña inválida")
token, _ = Token.objects.get_or_create(user=user)
return Response(token.key)Explanation of the previous function
As you can see, since this is the resource we have to use for login, and since the entire Rest API is protected by auth tokens, we have to specifically indicate that the previous resource can be accessed without the need for this token to be present in the request we are sending; therefore, we use the `permission_classes` decorator with the value of `AllowAny` so that it is publicly accessible; otherwise, it is a simple credential check like the one we did previously to check the credentials; otherwise, we have the generation of the authentication token, to which we have to pass the user for whom we want to create or search, in case it exists, the token.
The function really explains itself, we have the parameters we receive via a post request, in this case we use the same users that Django uses internally throughout the application. Therefore, the custom login process uses the `check_password` function that Django provides for this purpose; now, from Postman we can consume the previous function.
Testing authentication in Postman
By sending a POST request to /login, you will receive a token. Then, use that token in the headers (`Authorization: Token
When I tested this flow for the first time, I was surprised how simple it is to protect an entire API with DRF: all you need is to configure a couple of classes in the settings.py and adjust the permissions.

And if the login goes well, we create (in case it doesn't exist) and return the authentication token that our user has to use to make requests.
Then we create the route for this function:
urlpatterns = route.urls
urlpatterns += path('login',views.login),And now, when we want to make a request, we have to send the token; for example, using Postman:

Protection of ModelViewSet
We can add the following configuration to our class (in case you want to make it local to a class, you can avoid the `DEFAULT_PERMISSION_CLASSES` configuration); one of the properties that any Rest class has is the following:
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from .models import Category
from .serializers import CategorySerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
permission_classes = [IsAuthenticated] # Only auth userIt is necessary to be authenticated `DEFAULT_PERMISSION_CLASSES` and the next is that we are going to use the token system as the backend; now, we also have to indicate that we are going to use the tokens application.
This is useful if we are NOT using Django's migration system, in cases - for example - where we are using MongoDB with Django, which at least for handling the tables/collections created by us, it should not be necessary to apply the migrations.
This means that all requests to /categories/ require authentication, that is:
If the user is not authenticated, they will receive:
{
"detail": "Authentication credentials were not provided."
}With HTTP code 401 Unauthorized.
If the user IS authenticated, they will be able to access and use the endpoint normally.
I agree to receive announcements of interest about this Blog.
A complete guide to building a REST API with Django and the Django REST Framework (DRF). Discover how to structure your project, use ViewSets, and secure your API with token-based authentication.