Django is a popular web framework for Python that provides many features to create web applications. One of these features is the Django REST framework, which is a powerful and flexible toolkit for building web APIs. In this blog post, we will learn how to use Django REST framework to create a simple API that can perform CRUD (Create, Read, Update, and Delete) operations on an entity. We will also add authentication to our API, so that only authorized users can access and modify the data.
What is Django REST framework?
Django REST framework is an extension of Django that provides a set of tools and libraries to build web APIs. Django REST framework makes it easy to:
- Define the data models and serializers for the API
- Create the views and routers for the API endpoints
- Add authentication and permissions to the API
- Test and document the API
- Customize and extend the API functionality
Django REST framework follows the RESTful principles and supports various data formats, such as JSON, XML, YAML, etc. It also provides a browsable API interface that allows users to explore and interact with the API directly from the web browser.
How to install Django and Django REST framework?
To use Django and Django REST framework, we need to have Python installed on our system. We can check the Python version by running the following command in the terminal:
python --version
We also need to create a virtual environment to isolate the dependencies of our project. We can use the venv
module to create and activate a virtual environment:
python -m venv env source env/bin/activate
Next, we need to install Django and Django REST framework using the pip
command:
pip install django pip install djangorestframework
We can verify the installation by running the following command:
pip freeze
This should show the versions of Django and Django REST framework that we have installed.
How to create a Django project and app?
To start a new Django project, we can use the django-admin
command:
django-admin startproject api_project
This will create a folder called api_project
with the following structure:
api_project/ manage.py api_project/ __init__.py settings.py urls.py asgi.py wsgi.py
The manage.py
file is a utility script that allows us to run various commands for our project, such as creating apps, running the server, migrating the database, etc. The api_project
folder contains the configuration files for our project, such as settings.py
, urls.py
, asgi.py
, and wsgi.py
.
To create a new app for our project, we can use the startapp
command:
python manage.py startapp api_app
This will create a folder called api_app
with the following structure:
api_app/ __init__.py admin.py apps.py models.py tests.py views.py migrations/ __init__.py
The api_app
folder contains the files for our app, such as models.py
, views.py
, admin.py
, etc. The migrations
folder contains the files for the database migrations, which are the changes that we make to our data models.
To register our app with our project, we need to add api_app
and rest_framework
to the INSTALLED_APPS
list in the settings.py
file:
# settings.py INSTALLED_APPS = [ # ... 'api_app', 'rest_framework', ]
We also need to include the api_app
URLs in the urls.py
file of our project:
# urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api_app.urls')), ]
We use the include
function to delegate the URL patterns to the api_app
app. We also prefix the api_app
URLs with api/
, so that they are distinct from the other URLs of our project.
How to define the data model and serializer for the API?
The data model is the representation of the data that we want to store and manipulate in our API. The data model defines the properties and relationships of the entities that we want to expose through the API. In Django, we can define the data model using the models
module, which provides various classes and fields to create the database tables and columns.
For this blog post, we will create a simple data model for a Book
entity, which has the following properties:
title
: The title of the bookauthor
: The author of the bookdescription
: A brief description of the bookpublished
: The date when the book was published
We can define the Book
model in the models.py
file of our app:
# models.py from django.db import models class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=100) description = models.TextField() published = models.DateField() def __str__(self): return self.title
We use the models.Model
class as the base class for our model, and we use various field classes to define the attributes of our model. We also define a __str__
method to return a human-readable representation of our model.
To create the database table for our model, we need to run the following commands:
python manage.py makemigrations python manage.py migrate
The makemigrations
command will generate a migration file in the migrations
folder, which contains the SQL commands to create the table and columns for our model. The migrate
command will execute the migration file and apply the changes to the database.
The serializer is the component that converts the data model to and from a format that can be transmitted over the network, such as JSON or XML. The serializer also validates the data and handles the errors. In Django REST framework, we can define the serializer using the serializers
module, which provides various classes and fields to create the serializer.
We can define the BookSerializer
in the serializers.py
file of our app:
# serializers.py from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = '__all__'
We use the serializers.ModelSerializer
class as the base class for our serializer, and we specify the model
and the fields
that we want to include in the serializer. We use the __all__
value to include all the fields of the model. We can also customize the serializer by adding or overriding the fields and methods.
How to create the views and routers for the API endpoints?
The views are the components that handle the requests and responses for the API endpoints. The views define the logic and behavior of the API, such as what data to return, what actions to perform, what status codes to send, etc. In Django REST framework, we can create the views using the views
module, which provides various classes and mixins to create the views.
We can create the BookViewSet
in the views.py
file of our app:
# urls.py from django.urls import path, include from rest_framework import routers from .views import BookViewSet router = routers.DefaultRouter() router.register('books', BookViewSet) urlpatterns = [ path('', include(router.urls)), ]
We use the routers.DefaultRouter
class to create a default router, and we use the register
method to register the BookViewSet
with the router. The router will automatically generate the URL patterns for the BookViewSet
, such as:
api/books/
: The list and create endpoint for the booksapi/books/<id>/
: The retrieve, update, and destroy endpoint for a specific book
We can also customize the router by adding or overriding the methods and attributes.
How to add authentication and permissions to the API?
Authentication is the process of verifying the identity of the user who is accessing the API. Authentication ensures that only authorized users can access the data and perform the actions that they are allowed to do. Permissions are the rules that determine what actions the user can perform on the data. Permissions ensure that the user can only access and modify the data that they are authorized to do.
In Django REST framework, we can add authentication and permissions to the API using the authentication
and permissions
modules, which provide various classes and methods to implement the authentication and permissions.
For this blog post, we will use the TokenAuthentication
and the IsAuthenticated
classes to add authentication and permissions to our API. The TokenAuthentication
class is a simple authentication scheme that uses a token to identify the user. The IsAuthenticated
class is a simple permission class that only allows access to authenticated users.
To use the TokenAuthentication
class, we need to install the rest_framework.authtoken
app and run the migrations:
pip install djangorestframework.authtoken
# settings.py INSTALLED_APPS = [ # ... 'rest_framework.authtoken', ]
python manage.py makemigrations python manage.py migrate
The rest_framework.authtoken
app will create a table called authtoken_token
in the database, which will store the tokens for the users. The tokens are randomly generated strings that are assigned to the users when they register or log in.
To use the IsAuthenticated
class, we need to add it to the permission_classes
attribute of our view:
# views.py from rest_framework import viewsets, permissions from .models import Book from .serializers import BookSerializer class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer permission_classes = [permissions.IsAuthenticated]
The permission_classes
attribute is a list of permission classes that are applied to the view. The IsAuthenticated
class will check if the user is authenticated before allowing access to the view. If the user is not authenticated, the view will return a 401 Unauthorized
response.
To test the authentication and permissions of our API, we need to obtain a token for the user and include it in the request header. We can use the obtain_auth_token
view provided by the rest_framework.authtoken
app to get a token for the user:
curl -X POST http://localhost:8000/api-token-auth/ -d "username=admin&password=admin"
This will return a JSON response with the token for the user:
{"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"}
We can then use the token to access the API endpoints by adding the Authorization
header to the request:
curl -X GET http://localhost:8000/api/books/ -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"
This will return a JSON response with the list of books:
JSON
[ { "id": 1, "title": "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams", "description": "A classic science fiction comedy novel", "published": "1979-10-12" }, { "id": 2, "title": "The Lord of the Rings", "author": "J.R.R. Tolkien", "description": "An epic fantasy adventure trilogy", "published": "1954-07-29" } ]
If we try to access the API endpoints without the token, or with an invalid token, we will get a 401 Unauthorized
response:
curl -X GET http://localhost:8000/api/books/
{"detail": "Authentication credentials were not provided."}