← Back to all posts

Building a REST API with Django REST Framework from Scratch

A complete walkthrough of setting up DRF with JWT authentication, custom permissions, and pagination — the way I actually do it in production.

Why Django REST Framework?

When I started building APIs with Python, I tried Flask first. It's lightweight and flexible, but as the project grew, I found myself reinventing things that DRF already solves well — authentication, serialization, permissions, pagination.

DRF gives you a solid foundation without locking you into magic. Let's build something real.

Project Setup

Start with a clean virtual environment:

# Create and activate virtualenv
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Install dependencies
pip install django djangorestframework djangorestframework-simplejwt

Then create your project:

django-admin startproject myapi .
python manage.py startapp blog

Settings Configuration

Add DRF to your installed apps and configure the default authentication:

# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'blog',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
}

Creating the Model

# blog/models.py
from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

Serializer

# blog/serializers.py
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    author_name = serializers.CharField(source='author.username', read_only=True)

    class Meta:
        model = Post
        fields = ['id', 'title', 'content', 'author_name', 'created_at']

ViewSet

# blog/views.py
from rest_framework import viewsets, permissions
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all().order_by('-created_at')
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

That's the Core!

With this setup you get full CRUD endpoints automatically. Wire up your URLs and run migrations, and you have a working API with JWT auth and pagination out of the box.

💡

In production, always set DEBUG = False and configure ALLOWED_HOSTS properly. Never expose your SECRET_KEY.