Categories
How To Guides

Creating a REST API with Django

Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. It’s well-suited for creating powerful web applications and APIs. In this comprehensive guide, we will walk through the steps to create a REST API with Django using Django REST framework (DRF), covering everything from setting up the environment to deploying the application.

Table of Contents

  1. Introduction to REST APIs
  2. Setting Up the Django Environment
  3. Creating a New Django Project
  4. Setting Up Django REST Framework
  5. Creating Your First Endpoint
  6. Handling Different HTTP Methods
  7. Using Django Models and Serializers
  8. Implementing Authentication
  9. Error Handling and Validation
  10. Testing Your API
  11. Documentation with Swagger
  12. Deployment
  13. Conclusion

1. Introduction to REST APIs

REST (Representational State Transfer) is an architectural style for designing networked applications. It relies on a stateless, client-server, cacheable communication protocol — the HTTP. RESTful applications use HTTP requests to perform CRUD (Create, Read, Update, Delete) operations on resources, which can be represented in formats like JSON or XML.

Key Concepts

  • Resource: Any object that can be accessed via a URI.
  • URI (Uniform Resource Identifier): A unique identifier for a resource.
  • HTTP Methods: Common methods include GET, POST, PUT, DELETE.

2. Setting Up the Django Environment

Installing Django and Django REST Framework

First, ensure you have Python installed. You can download it from the official website. Then, install Django and Django REST framework using pip:

bash

pip install django djangorestframework

Creating a Virtual Environment

It’s good practice to create a virtual environment for your project to manage dependencies:

bash

python -m venv myenv
source myenv/bin/activate # On Windows use `myenv\Scripts\activate`

3. Creating a New Django Project

Starting a New Project

Create a new Django project with the following command:

bash

django-admin startproject myproject
cd myproject

Starting a New App

In Django, applications are components of your project. Create a new app within your project:

bash

python manage.py startapp myapp

Adding the App to INSTALLED_APPS

Edit myproject/settings.py to include myapp and rest_framework in the INSTALLED_APPS list:

python

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

4. Setting Up Django REST Framework

Configuring Django REST Framework

Add basic settings for Django REST framework in myproject/settings.py:

python

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}

5. Creating Your First Endpoint

Defining Models

In myapp/models.py, define a simple model:

python

from django.db import models

class Item(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()

def __str__(self):
return self.name

Making Migrations

Create the database schema for the models:

bash

python manage.py makemigrations
python manage.py migrate

Creating Serializers

Serializers define how the model instances are converted to JSON. Create a file myapp/serializers.py:

python

from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ['id', 'name', 'description']

Defining Views

Create views to handle API requests in myapp/views.py:

python

from rest_framework import generics
from .models import Item
from .serializers import ItemSerializer

class ItemListCreate(generics.ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer

class ItemDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer

Adding URL Patterns

Define URL patterns to route requests to the views in myapp/urls.py:

python

from django.urls import path
from .views import ItemListCreate, ItemDetail

urlpatterns = [
path('items/', ItemListCreate.as_view(), name='item-list-create'),
path('items/<int:pk>/', ItemDetail.as_view(), name='item-detail'),
]

Include these URL patterns in the project’s main urls.py:

python

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

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

6. Handling Different HTTP Methods

List and Create (GET and POST)

The ItemListCreate view handles GET (list items) and POST (create new item) requests.

Retrieve, Update, and Delete (GET, PUT, DELETE)

The ItemDetail view handles GET (retrieve item), PUT (update item), and DELETE (delete item) requests.

7. Using Django Models and Serializers

Customizing Serializers

You can customize serializers to include additional validations or computed fields.

python

from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
name_uppercase = serializers.SerializerMethodField()

class Meta:
model = Item
fields = ['id', 'name', 'description', 'name_uppercase']

def get_name_uppercase(self, obj):
return obj.name.upper()

Serializer Validation

You can add custom validation methods in serializers:

python

class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ['id', 'name', 'description']

def validate_name(self, value):
if 'bad' in value.lower():
raise serializers.ValidationError("Name contains inappropriate word.")
return value

8. Implementing Authentication

Adding Token Authentication

Install the djangorestframework-simplejwt package for JWT authentication:

bash

pip install djangorestframework-simplejwt

Configure the authentication in myproject/settings.py:

python

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}

Update the urls.py to include JWT endpoints:

python

from django.urls import path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

9. Error Handling and Validation

Custom Error Handling

You can create custom exception handlers. Add the following in myproject/settings.py:

python

REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'myproject.exceptions.custom_exception_handler',
}

Create the exceptions.py file:

python

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
response = exception_handler(exc, context)

if response is not None:
response.data['status_code'] = response.status_code

return response

Model Validation

You can add validation directly in models:

python

from django.core.exceptions import ValidationError

class Item(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()

def clean(self):
if 'bad' in self.name.lower():
raise ValidationError("Name contains inappropriate word.")

10. Testing Your API

Writing Tests

Create tests in myapp/tests.py:

python

from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Item

class ItemTests(APITestCase):
def test_create_item(self):
url = reverse('item-list-create')
data = {'name': 'Test Item', 'description': 'A test item'}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Item.objects.count(), 1)
self.assertEqual(Item.objects.get().name, 'Test Item')

def test_get_items(self):
url = reverse('item-list-create')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)

Running Tests

Run the tests with the following command:

bash

python manage.py test

11. Documentation with Swagger

Setting Up Swagger

Swagger is a tool for documenting APIs. You can use the drf-yasg library for automatic documentation generation:

bash

pip install drf-yasg

Add the following to your urls.py:

python

from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
openapi.Info(
title="My API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="[email protected]"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]

Now, navigate to http://127.0.0.1:8000/swagger/ to see the Swagger documentation.

12. Deployment

Using Gunicorn

Gunicorn is a Python WSGI HTTP Server for UNIX. It’s a pre-fork worker model, which means it forks multiple worker processes to handle requests.

Install Gunicorn:

bash

pip install gunicorn

Run your Django app with Gunicorn:

bash

gunicorn myproject.wsgi:application

Deploying to Heroku

Heroku is a cloud platform that lets you deploy, manage, and scale apps.

  1. Install the Heroku CLI.
  2. Create a Procfile with the following content:
    Procfile

    web: gunicorn myproject.wsgi
  3. Create requirements.txt with:
    bash

    pip freeze > requirements.txt
  4. Deploy your app:
    bash

    heroku create
    git add .
    git commit -m "Initial commit"
    git push heroku master

Configuring Static Files

Configure your static files for production. Add the following in myproject/settings.py:

python

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

Run the collectstatic management command:

bash

python manage.py collectstatic

13. Conclusion

Creating a REST API with Django and Django REST framework is a powerful way to build web applications and APIs. Django provides a robust and scalable framework, while Django REST framework adds flexibility and convenience for building APIs. By following best practices and utilizing the extensive features of Django and DRF, you can create efficient, secure, and well-documented APIs.

This comprehensive guide has covered the basics of setting up a Django project, creating models and serializers, defining views, implementing authentication, error handling, testing, documentation, and deployment. With this knowledge, you are well-equipped to start building your own REST APIs with Django and Django REST framework.