Learn / Frameworks / Django / Building a JSON API

Intermediate 15 min

Building a JSON API

Return JSON from views and expose a REST API with Django REST framework.

What you will learn

  • Return JsonResponse
  • Write a serializer
  • Use a ModelViewSet

Modern apps often serve JSON to a React front end or a mobile app instead of HTML pages. Django can do that natively, and the Django REST framework (DRF) makes it fast to build a full API.

from django.http import JsonResponse
from .models import Post

def api_posts(request):
    data = list(Post.objects.filter(published=True).values("id", "title", "created"))
    return JsonResponse({"posts": data})
pip install djangorestframework

Add "rest_framework" to INSTALLED_APPS. DRF has three main pieces: serializers, viewsets and routers.

Serializers

A serializer converts model instances to JSON and validates incoming JSON, much like a form.

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

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

    class Meta:
        model = Post
        fields = ["id", "title", "body", "published", "author", "author_name", "created"]
        read_only_fields = ["created"]

ViewSets and routers

A ModelViewSet provides list, create, retrieve, update and delete in a few lines.

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

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.select_related("author")
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

# mysite/urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("posts", PostViewSet)
urlpatterns += [path("api/", include(router.urls))]

That gives you GET /api/posts/, POST /api/posts/, GET /api/posts/1/, PUT, PATCH and DELETE, plus a browsable HTML interface for testing.

curl http://127.0.0.1:8000/api/posts/
curl -X POST http://127.0.0.1:8000/api/posts/ \
  -H "Content-Type: application/json" \
  -d '{"title": "Hello API", "body": "text", "author": 1}'
# settings.py
REST_FRAMEWORK = {
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 20,
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",
        "rest_framework.authentication.TokenAuthentication",
    ],
}
Consider FastAPI too

If you only need an API and want automatic docs and type-based validation, the FastAPI course in this section is a lighter alternative. Django shines when you also want the admin, auth and ORM together.

Try it yourself

Add a custom action on the viewset: POST /api/posts/1/publish/ that sets published=True and returns the updated post.

Show solution
from rest_framework.decorators import action
from rest_framework.response import Response

class PostViewSet(viewsets.ModelViewSet):
    ...
    @action(detail=True, methods=["post"])
    def publish(self, request, pk=None):
        post = self.get_object()
        post.published = True
        post.save()
        return Response(self.get_serializer(post).data)