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 djangorestframeworkAdd "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",
],
}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)