Django REST Framework Intro

Reviewed & published by Brayan K

Django REST Framework (DRF) is a powerful toolkit built on top of Django for building Web APIs — it turns your Django models into JSON endpoints that web and mobile clients can consume, handling serialization, request parsing, authentication, and browsable API documentation for you.

Part of the free Django course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll install DRF, learn what a REST API and JSON really are, write your first API view with the @api_view decorator, and explore status codes, the Request and Response objects, and the browsable API.

What You'll Learn in This Lesson

1 Installing DRF & What a REST API Is

A REST API is a way for programs to talk to each other over HTTP. Instead of returning an HTML page meant for a human to read, an API returns structured data — usually JSON — that another program can parse. A React front-end or a mobile app sends a request to a URL and gets back data it can display however it likes.

JSON (JavaScript Object Notation) looks almost exactly like a Python dictionary. A single user might be represented as {"id": 1, "name": "Alice"}. Because JSON maps so cleanly onto Python dicts and lists, DRF can convert your models into JSON with very little work from you.

Django REST Framework is installed with pip, then registered in your project's INSTALLED_APPS so Django loads it.

# 1. Install Django REST Framework
pip install djangorestframework

# 2. Add it to INSTALLED_APPS in settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",          # <-- add DRF here
    "myapp",
]
# A REST API sends JSON. JSON looks just like a Python dict.
# Let's build a dictionary and serialize it to JSON text the way an
# API endpoint would before sending it back to a client.

import json

# This is the kind of Python object a Django model would produce.
user = {"id": 1, "name": "Alice", "is_active": True}

# json.dumps turns the dict into a JSON string (the API response body).
json_text = json.dumps(user)
print("JSON sent to the client:")
print(json_text)

# A client (React, mobile app) parses it back into data with json.loads.
parsed = json.loads(json_text)
print("Client read name:", parsed["name"])

# ✅ Expected output:
# JSON sent to the client:
# {"id": 1, "name": "Alice", "is_active": true}
# Client read name: Alice

2 Your First API View with @api_view

In plain Django you write views that return an HttpResponse. In DRF you decorate a function with @api_view and return a DRF Response object. DRF then takes care of converting your Python data into JSON automatically.

The @api_view decorator takes a list of the HTTP methods the view accepts, such as ['GET'] or ['GET', 'POST']. If a client uses a method that isn't in the list, DRF returns a 405 Method Not Allowed response for you.

# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET'])
def hello_api(request):
    data = {"message": "Hello, API!", "method": request.method}
    return Response(data)        # DRF serializes this dict to JSON


# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("api/hello/", views.hello_api),
]

Visiting /api/hello/ now returns JSON like {"message": "Hello, API!", "method": "GET"}. Notice you returned a Python dict — DRF's Response handled the JSON conversion.

# Let's simulate what the hello_api view does. In real DRF you import
# Response from rest_framework, but here we mimic it in plain Python so
# you can see the data flow: build a dict, then serialize to JSON.

import json

def hello_api(request):
    # request is a dict here standing in for the DRF request object.
    data = {"message": "Hello, API!", "method": request["method"]}
    return data   # In real DRF: return Response(data)

# Simulate DRF calling your view with an incoming GET request.
fake_request = {"method": "GET", "path": "/api/hello/"}
response_data = hello_api(fake_request)

# DRF would serialize the returned dict into this JSON body:
print(json.dumps(response_data))

# ✅ Expected output:
# {"message": "Hello, API!", "method": "GET"}

3 Status Codes, Request/Response & the Browsable API

Every HTTP response carries a status code that tells the client what happened. DRF gives you readable constants in the status module so you don't have to memorize raw numbers like 201 or 404.

Inside the view, DRF gives you an enhanced Request object: request.method is the HTTP method, and request.data holds parsed JSON sent by the client (no manual parsing needed). You build a Response by passing your data and, optionally, a status code.

# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET', 'POST'])
def items_api(request):
    if request.method == 'POST':
        new_item = request.data          # parsed JSON from the client
        return Response(new_item, status=status.HTTP_201_CREATED)

    items = [{"id": 1, "name": "Pen"}, {"id": 2, "name": "Notebook"}]
    return Response(items, status=status.HTTP_200_OK)
# Simulate the items_api view handling both GET and POST, choosing a
# status code for each. We mimic Response(data, status=...) with a dict.

import json

HTTP_200_OK = 200
HTTP_201_CREATED = 201

def items_api(request):
    if request["method"] == "POST":
        new_item = request["data"]
        return {"body": new_item, "status": HTTP_201_CREATED}
    items = [{"id": 1, "name": "Pen"}, {"id": 2, "name": "Notebook"}]
    return {"body": items, "status": HTTP_200_OK}

# A GET request lists items with status 200.
get_resp = items_api({"method": "GET", "data": None})
print("GET status:", get_resp["status"])
print("GET body:", json.dumps(get_resp["body"]))

# A POST request creates an item and returns status 201.
post_resp = items_api({"method": "POST", "data": {"id": 3, "name": "Eraser"}})
print("POST status:", post_resp["status"])
print("POST body:", json.dumps(post_resp["body"]))

# ✅ Expected output:
# GET status: 200
# GET body: [{"id": 1, "name": "Pen"}, {"id": 2, "name": "Notebook"}]
# POST status: 201
# POST body: {"id": 3, "name": "Eraser"}

🎯 Your Turn: Complete the API View

Fill in the blanks so this view only allows GET requests and returns its data correctly. Replace each ___.

# 🎯 YOUR TURN: this mimics the real DRF pattern below.
#
#   @api_view(['GET'])          <-- decorator lists allowed methods
#   def profile_api(request):
#       return Response(data)   <-- Response wraps your dict
#
# Replace the first ___ with the allowed method string "GET"
# Replace the second ___ with the word  data

def make_response(method, data):
    return {"allowed": [method], "body": data}

allowed_method = "___"          # should be "GET"
profile = {"id": 7, "name": "Sam"}
result = make_response(allowed_method, ___)   # pass the profile dict

print(result)

# EXPECTED OUTPUT:
# {'allowed': ['GET'], 'body': {'id': 7, 'name': 'Sam'}}

Common Errors (And How to Fix Them)

❌ The browsable API and DRF features don't work

You forgot to add 'rest_framework' to INSTALLED_APPS in settings.py.

✅ Fix: add "rest_framework" to the INSTALLED_APPS list and restart the server.

❌ Returning JsonResponse instead of DRF's Response

Using Django's JsonResponse skips DRF's renderers, so you lose the browsable API and content negotiation.

✅ Fix: import from rest_framework.response import Response and return Response(data) instead.

❌ 405 Method Not Allowed

The HTTP method the client used isn't listed in your @api_view decorator.

✅ Fix: include the method, e.g. @api_view(['GET', 'POST']) to allow both GET and POST.

📋 Quick Reference

ToolWhat It Does
@api_view(['GET'])Turn a function into an API view and list allowed methods
Response(data)Return data that DRF serializes to JSON
status.HTTP_201_CREATEDReadable HTTP status code constants
serializers.SerializerConvert models to/from JSON (covered next lesson)
'rest_framework'Add to INSTALLED_APPS to enable DRF

🏆 Mini Challenge: A Mini API Endpoint

Build a function that acts like an API endpoint: it takes a request method, returns a list of books for GET, and a 201-style response when a new book is posted.

# 🏆 Mini Challenge: simulate a books API endpoint.
# Return a 200 list for GET and a 201 created response for POST.

import json

HTTP_200_OK = 200
HTTP_201_CREATED = 201

books = [
    {"id": 1, "title": "Python 101"},
    {"id": 2, "title": "Django Deep Dive"},
]

def books_api(request):
    if request["method"] == "POST":
        new_book = request["data"]
        books.append(new_book)
        return {"body": new_book, "status": HTTP_201_CREATED}
    return {"body": books, "status": HTTP_200_OK}

# List existing books
print("GET ->", json.dumps(books_api({"method": "GET", "data": None})))

# Create a new book
created = books_api({"method": "POST", "data": {"id": 3, "title": "DRF Basics"}})
print("POST ->", json.dumps(created))

# EXPECTED: GET returns status 200 with two books,
# POST returns status 201 with the new book added.

❓ Frequently Asked Questions

Lesson complete — you built your first DRF API!

You installed Django REST Framework, registered it in INSTALLED_APPS, learned what REST APIs and JSON are, wrote a view with @api_view that returns a Response, and used status codes plus the browsable API.

Practice quiz

What does Django REST Framework primarily help you build?

  • HTML templates
  • Web APIs that return JSON
  • Database migrations
  • CSS stylesheets

Answer: Web APIs that return JSON. DRF builds Web APIs on top of Django, returning JSON instead of rendered HTML.

Which decorator turns a function into a DRF API view?

  • @login_required
  • @csrf_exempt
  • @api_view
  • @require_GET

Answer: @api_view. @api_view marks a function as a DRF view and handles JSON conversion.

What does the @api_view decorator take as its argument?

  • A list of allowed HTTP methods like ['GET', 'POST']
  • A template name
  • A serializer class
  • A URL pattern

Answer: A list of allowed HTTP methods like ['GET', 'POST']. @api_view(['GET', 'POST']) lists which HTTP methods the view accepts.

What object should a DRF API view return?

  • An HttpResponse
  • A render() call
  • A JsonResponse from Django
  • A DRF Response object

Answer: A DRF Response object. DRF views return a Response object, which DRF serializes to JSON automatically.

What status code does DRF return if a client uses a method not in @api_view?

  • 405 Method Not Allowed
  • 404 Not Found
  • 500 Server Error
  • 200 OK

Answer: 405 Method Not Allowed. DRF returns 405 Method Not Allowed when the method isn't listed in the decorator.

What is JSON?

  • A Python web server
  • A lightweight text data format that maps to dicts and lists
  • A Django template engine
  • A type of database

Answer: A lightweight text data format that maps to dicts and lists. JSON is a lightweight, text-based format that maps cleanly to Python dicts and lists.

Is DRF part of Django core or a separate package?

  • Built into Django core
  • Only in Django 5+
  • A third-party package installed on top of Django
  • Part of the standard library

Answer: A third-party package installed on top of Django. DRF is a third-party package added to INSTALLED_APPS, sitting on top of Django.

What status code constant signals a successful creation in DRF?

  • status.HTTP_404_NOT_FOUND
  • status.HTTP_500_INTERNAL_SERVER_ERROR
  • status.HTTP_204_NO_CONTENT
  • status.HTTP_201_CREATED

Answer: status.HTTP_201_CREATED. 201 Created signals a resource was successfully created; DRF exposes it as status.HTTP_201_CREATED.

What handy feature does DRF provide for testing endpoints in a browser?

  • The browsable API
  • A SQL console
  • A migration viewer
  • A template debugger

Answer: The browsable API. DRF ships a browsable HTML API interface for exploring and testing endpoints.

Should you know Django basics before learning DRF?

  • No, DRF replaces Django entirely
  • Yes — DRF builds on models, URLs, and views
  • Only the admin is required
  • Only templates are required

Answer: Yes — DRF builds on models, URLs, and views. DRF builds directly on Django models, URL patterns, and views.

Continue this course

Frequently asked questions

What is Django REST Framework used for?

Django REST Framework (DRF) is used to build Web APIs on top of Django. Instead of returning HTML pages, your endpoints return JSON that web front-ends (React, Vue), mobile apps, and other services can consume. DRF handles serialization (turning model instances into JSON and back), request parsing, authentication, permissions, and even a browsable HTML interface for testing — so you write far less boilerplate than rolling your own API by hand.

What is the difference between Django and Django REST Framework?

Django is the underlying web framework: it gives you the ORM, URL routing, views, and templates for building full HTML websites. Django REST Framework is a third-party package that sits on top of Django and specializes in API responses. You still use Django models and URLs, but DRF adds serializers, the @api_view decorator, Response objects, status codes, and ViewSets so your views return JSON instead of rendered pages.

What is JSON and why do APIs use it?

JSON (JavaScript Object Notation) is a lightweight, text-based data format that looks like Python dictionaries and lists. APIs use it because almost every programming language can read and write JSON easily, it is human-readable, and it maps cleanly to objects in JavaScript and dictionaries in Python. When a client requests data from your DRF API, DRF serializes your Python objects into JSON text and sends it back over HTTP.

Do I need to know Django before learning DRF?

Yes. DRF builds directly on Django concepts — models, the ORM, URL patterns, and views. You should be comfortable defining models, wiring up URLs, and writing basic views before adding DRF. Once those fundamentals are solid, DRF mostly changes how your views return data: instead of an HttpResponse with HTML, you return a Response with serialized JSON.