0% found this document useful (0 votes)
207 views66 pages

Learn Django REST Framework Basics

The document outlines a structured course on Django REST Framework (DRF) for users with basic Django knowledge. It includes a detailed syllabus covering topics such as installation, serializers, views, authentication, and real-world project implementation. The course emphasizes practical exercises and examples to reinforce learning and understanding of API development using DRF.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
207 views66 pages

Learn Django REST Framework Basics

The document outlines a structured course on Django REST Framework (DRF) for users with basic Django knowledge. It includes a detailed syllabus covering topics such as installation, serializers, views, authentication, and real-world project implementation. The course emphasizes practical exercises and examples to reinforce learning and understanding of API development using DRF.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Teach me django rest framework

Perfect! Let’s dive into Django REST Framework (DRF). Since you want a structured, step-by-step
approach, we’ll treat this as a full interactive course.

Before we outline the syllabus, a quick clarifying question: do you already have basic Django
knowledge (models, views, URLs) or should we include a short refresher on Django first?

I have basic knowledge

Great! Since you already know Django basics, we can dive directly into Django REST Framework (DRF).
Here’s a structured syllabus I suggest, progressing from fundamentals to advanced concepts:

DRF Syllabus
Module 1: Introduction and Setup

1. Installing DRF

2. Setting up a DRF project

3. Understanding REST APIs and why DRF is useful

Module 2: Serializers

1. What serializers are and why we need them


2. Creating serializers for models

3. Validations and custom serializer fields

Module 3: Views & ViewSets

1. Function-based views vs Class-based views

2. DRF generic views


3. ViewSets and Routers

Module 4: URLs & Routing

1. Connecting views to URLs

2. Using Routers with ViewSets


3. Nested routes (optional advanced)

Module 5: Authentication & Permissions


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 1/66
1. Built-in authentication schemes
2. Permissions (AllowAny, IsAuthenticated, custom)

3. Token-based and JWT authentication

Module 6: Advanced Features

1. Filtering, searching, and ordering

2. Pagination
3. Throttling and rate-limiting

Module 7: Testing & Best Practices

1. Writing API tests

2. Structuring your API project


3. Versioning and API documentation (Swagger/OpenAPI)

Module 8: Real-world Example Project

1. Building a small API (e.g., blog or todo app)

2. Integrating all learned concepts

3. Deploying the API

We can start Module 1: Introduction and Setup immediately.


Lesson 1.1: Installing DRF & Setting Up the Project

Concept: DRF is a Django library that helps you build RESTful APIs efficiently. You don’t reinvent the
wheel for serialization, authentication, and routing.

Analogy: Think of Django as your kitchen, and DRF as a set of high-quality appliances that help
you cook APIs quickly and cleanly.

Step 1: Install DRF

bash

pip install djangorestframework

Step 2: Add to INSTALLED_APPS in [Link]

python

INSTALLED_APPS = [
...
'rest_framework',
]

Step 3: Test installation


Run the server and check [Link] (or create a simple API view later to verify).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 2/66
Socratic Question:
Why do you think we need a separate library like DRF instead of just using Django views for APIs?
Exercise:
Install DRF in a Django project you already have, add it to INSTALLED_APPS, and confirm there are no
errors when you run the server.

Once you do that, we’ll move to Module 2: Serializers, which is where the real power of DRF starts.

Do you want to try the installation first, or should I explain serializers next?

Move

Perfect! Let’s move on to Module 2: Serializers, which is central to how DRF works.

Lesson 2.1: What Serializers Are and Why We Need Them


Concept:
In DRF, serializers convert complex data types (like Django models) into JSON, which can be sent
over HTTP. They also do the reverse: convert JSON from clients into Python objects you can save in
your database.
Analogy:
Think of serializers as translators between your database and the outside world. If your database
speaks “Python” and the client speaks “JSON,” the serializer is the translator making both sides
understand each other.
Example:
Suppose you have a simple Book model:

python

from [Link] import models

class Book([Link]):
title = [Link](max_length=100)
author = [Link](max_length=100)
published_date = [Link]()

A basic serializer for it would be:

python

from rest_framework import serializers


from .models import Book

class BookSerializer([Link]):
class Meta:
model = Book
fields = '__all__'

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 3/66
ModelSerializer automatically maps your model fields to JSON.

fields='__all__' tells DRF to include all fields.

Socratic Questions:

1. Why do you think we need serializers instead of just returning Python objects in a response?
2. Can you imagine a scenario where you’d want to exclude certain model fields from the API
response?

Exercise:
Create a serializer for a model you already have in your Django project. Try returning only a subset of
fields using fields = ['field1', 'field2'].

Do you want me to explain validations and custom serializer fields next, or should we practice
creating serializers with some examples first?

[Link] web unterstand js only


[Link] be some exclude keyword is there

Exactly! You nailed both points 👏


1. Yes — the web (clients like browsers, mobile apps) primarily communicates using JSON (JavaScript
Object Notation). Python objects (like Django models or QuerySets) aren’t directly understandable, so
serializers act as the bridge.

2. Yes again — DRF provides a neat way to exclude fields. You can either:
Use fields to include only specific ones

Or use exclude to leave out some

For example:

python

class BookSerializer([Link]):
class Meta:
model = Book
exclude = ['published_date'] # this will hide published_date

✅ Great progress so far! Now let’s move deeper into Lesson 2.2: Validations and Custom Serializer
Fields.

Concept:
Serializers don’t just translate data; they also validate it before saving to the database. For
example, if a user tries to send an empty string as a book title, the serializer can catch that and
return an error.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 4/66
Example with validation:

python

class BookSerializer([Link]):
class Meta:
model = Book
fields = '__all__'

def validate_title(self, value):


if "django" not in [Link]():
raise [Link]("Title must contain the word 'django'.")
return value

This adds a custom rule: every book’s title must contain “django.”

If someone sends "Python for Beginners" as a title, the API will reject it with a validation error.

Socratic Questions:

1. Why do you think it’s better to put validation inside the serializer instead of doing it later in the view?
2. Can you think of one validation rule that might make sense for a model in your project (e.g.,
username length, price not negative, etc.)?

Would you like me to:


👉 (a) go deeper into more validation & custom fields with examples, or
👉 (b) move on to Views & ViewSets, where we’ll see how to actually return serialized data via an API
endpoint?

1.
2.

Nice — you chose (a) more on validations & custom fields 👍 Let’s dig in.
Lesson 2.3: Advanced Validation & Custom Fields
1. Field-level validation

Example: ensuring price is non-negative

python

class ProductSerializer([Link]):
class Meta:
model = Product
fields = '__all__'

def validate_price(self, value):

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 5/66
if value < 0:
raise [Link]("Price cannot be negative!")
return value

➡️ This runs whenever a price is provided.

2. Object-level validation

Example: making sure start_date is before end_date

python

class EventSerializer([Link]):
class Meta:
model = Event
fields = '__all__'

def validate(self, data):


if data['start_date'] > data['end_date']:
raise [Link]("Start date must be before end date.")
return data

➡️ This checks across multiple fields, not just one.


3. Custom fields

Sometimes you don’t want to store a field in the database but still want to expose it in the API.

Example: full_name from first_name + last_name

python

class UserSerializer([Link]):
full_name = [Link]()

class Meta:
model = User
fields = ['first_name', 'last_name', 'full_name']

def get_full_name(self, obj):


return f"{obj.first_name} {obj.last_name}"

➡️ Here doesn’t exist in the DB, but it appears in the API response.
full_name

✅ So far, serializers can:


Translate data between JSON ↔ Python

Validate fields (field-level & object-level)

Add custom computed fields

Socratic Questions for you:

1. When would you prefer object-level validation instead of field-level validation?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 6/66
2. Can you think of one custom field that might be useful in your project (e.g., age calculated from
date_of_birth)?

Mini Exercise:
Try writing a serializer for any model you have where:

One field must follow a rule (e.g., no negatives, or must contain “@”).
Add one computed field that doesn’t exist in the model.

Do you want me to:


👉 continue with custom serializer classes (non-ModelSerializer, manual fields),
or 👉 move on to Module 3: Views & ViewSets where we’ll start exposing data as APIs?

Move

Awesome 🚀 Let’s move to Module 3: Views & ViewSets — this is where serializers come alive and
actually serve data through APIs.

Lesson 3.1: Views in DRF


1. Function-Based Views (FBVs)

Just like normal Django views, but decorated with DRF tools.
Example:

python

from rest_framework.decorators import api_view


from rest_framework.response import Response

@api_view(['GET'])
def hello_world(request):
return Response({"message": "Hello, world!"})

➡️ Now when you hit this endpoint, you get a JSON response.
2. Class-Based Views (CBVs)

More reusable and organized.

Example with APIView:

python

from rest_framework.views import APIView


from rest_framework.response import Response

class HelloWorld(APIView):

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 7/66
def get(self, request):
return Response({"message": "Hello, class-based world!"})

➡️ CBVs let you define methods like get, post, put, delete neatly.

3. Generic Views (Powerful shortcuts)

DRF gives generic views to handle CRUD without boilerplate.

Example:

python

from rest_framework import generics


from .models import Book
from .serializers import BookSerializer

class BookListCreateView([Link]):
queryset = [Link]()
serializer_class = BookSerializer

➡️ With just a few lines, this gives you:


GET /books/ → list all books
POST /books/ → create a book

✅ Summary so far:
FBVs: simple, explicit

CBVs: structured, reusable

Generic Views: powerful shortcuts

Socratic Questions:

1. Why do you think generic views are preferred for most CRUD operations instead of writing
everything manually?

2. In what case might you still choose a function-based view instead of class-based or generic ones?

Exercise:
Create a ListCreateAPIView for one of your models (e.g., ProductListCreateView). Check if you can list
items and add a new one via POST.

Do you want me to:


👉 show Update/Delete with generic views,
or 👉 move directly into ViewSets & Routers (the most powerful abstraction in DRF)?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 8/66
[Link] boilerplate code
2. Do not know

Cover update and delete

Perfect answers again ✅


1. Exactly — less boilerplate code is why generic views are so widely used.
2. For function-based views (FBVs), they’re sometimes used when:

The logic is very simple (like a health-check endpoint).

You want super explicit control without class abstraction.

Lesson 3.2: Update & Delete with Generic Views


So far, we saw ListCreateAPIView (for list & create).
For retrieve, update, and delete, DRF gives more shortcuts:

1. RetrieveUpdateDestroyAPIView

Handles:

GET /books/1/ → retrieve single book

PUT /books/1/ → update

PATCH /books/1/ → partial update


DELETE /books/1/ → delete

python

from rest_framework import generics


from .models import Book
from .serializers import BookSerializer

class BookDetailView([Link]):
queryset = [Link]()
serializer_class = BookSerializer

2. Combining with ListCreateAPIView

Now you have:

/books/ → list & create

/books/<id>/ → retrieve, update, delete

➡️ Together, these two classes give you full CRUD API for a model with minimal code.
✅ At this point, you can:
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 9/66
List all items

Create a new one


Get a single item

Update it (full or partial)

Delete it

Socratic Questions:

1. Why do you think DRF provides both PUT (full update) and PATCH (partial update)?

2. Can you think of a real-world scenario where you’d only want to allow partial updates instead of
requiring full object replacement?

Mini Exercise:

Add a RetrieveUpdateDestroyAPIView for one of your models.


Test with PUT (sending all fields) and PATCH (sending only one field).

Do you want me to:


👉 dive into ViewSets & Routers next (a higher abstraction than generic views),
or 👉 pause to explore customizing generic views with extra logic?

Customize then move

Excellent choice 🎯 — let’s first see how to customize generic views, then we’ll move to ViewSets &
Routers.

Lesson 3.3: Customizing Generic Views


Generic views save a ton of boilerplate, but you’ll often need to tweak them for your project. Let’s
explore common customizations:

1. Filtering the queryset

By default, queryset = [Link]().


But you can override get_queryset to return data conditionally.

python

class BookListCreateView([Link]):
serializer_class = BookSerializer

def get_queryset(self):
# Only return books by the logged-in user

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 10/66
user = [Link]
return [Link](author=user)

2. Customizing behavior on create/update

You can override perform_create or perform_update to add extra logic.

python

class BookListCreateView([Link]):
queryset = [Link]()
serializer_class = BookSerializer

def perform_create(self, serializer):


# Automatically set logged-in user as author
[Link](author=[Link])

3. Custom responses

Sometimes you want to tweak the response instead of returning just serializer data.

python

class BookDetailView([Link]):
queryset = [Link]()
serializer_class = BookSerializer

def delete(self, request, *args, **kwargs):


instance = self.get_object()
self.perform_destroy(instance)
return Response({"message": "Book deleted successfully!"})

✅ So customizing generics usually means overriding:


get_queryset() → control what data is returned

perform_create() / perform_update() → add logic before saving


HTTP methods (get, post, delete, etc.) → change responses

Socratic Questions:

1. Why might it be useful to filter queryset based on the logged-in user?


2. Can you think of one piece of logic you’d want to add in perform_create (e.g., setting defaults,
logging, permissions)?

Mini Exercise:

Modify a generic view in your project so that it only returns objects created by the current user.

Shall I now take you into ViewSets & Routers (which make all this even cleaner), or do you want a mini
review quiz for everything in Views before moving on?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 11/66
[Link]
2. Before adding a Book title and description at the same time using perform create we also add
a new field call tax that automatically cluster is automatic help to cluster the books
automatically

Beautiful answers 🙌
1. Personalization — yes! Filtering by user ensures that each person only sees their own data (like their
own notes, todos, or orders).

2. Automatic logic in perform_create — exactly 💯 . Adding a field like tax automatically is a great
example of using business logic at the point of saving, without relying on the client to send it.

You’ve got the hang of customizing generic views really well 👌


✅ Quick Mini-Review (Views & Generics)
1. FBVs → simple, explicit

2. CBVs (APIView) → structured, reusable


3. Generic Views → shortcuts for CRUD (e.g., ListCreateAPIView, RetrieveUpdateDestroyAPIView)
4. Customization → override get_queryset, perform_create, perform_update, or response methods

Next step is a big one:


👉 ViewSets & Routers — they reduce even more boilerplate and make APIs cleaner.
Would you like me to jump straight into ViewSets now, or do you prefer I start with a side-by-side
comparison of Generic Views vs ViewSets so you can clearly see why ViewSets are so powerful?

Yes move

Perfect 🚀 Let’s dive into ViewSets & Routers, one of the most powerful features of DRF.
Lesson 3.4: ViewSets & Routers
1. What is a ViewSet?

A ViewSet is like a bundle of views (list, create, retrieve, update, delete) in a single class.

Instead of writing separate views for each action, you define them in one place.

2. Example: Using a ModelViewSet

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 12/66
Here’s the same CRUD for Book, but in just a few lines:

python

from rest_framework import viewsets


from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

➡️ That’s it. This single class gives you:


GET /books/ → list all

POST /books/ → create


GET /books/1/ → retrieve one
PUT /books/1/ → update

PATCH /books/1/ → partial update


DELETE /books/1/ → delete

3. Routers

Normally in Django you’d add URLs manually.

With routers, DRF automatically maps routes for you.

python

from rest_framework.routers import DefaultRouter


from [Link] import path, include
from .views import BookViewSet

router = DefaultRouter()
[Link](r'books', BookViewSet)

urlpatterns = [
path('', include([Link])),
]

➡️ Now /books/ and /books/<id>/ are auto-generated!

4. Customizing a ViewSet

You can still customize just like generics:

python

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

def perform_create(self, serializer):


[Link](author=[Link]) # auto-assign logged-in user

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 13/66
✅ Summary so far:
Generic Views = shortcut per view (list, create, etc.)
ViewSets = bundle all CRUD into one class

Routers = auto-generate URLs for ViewSets

Socratic Questions:

1. Why do you think ViewSets + Routers are more scalable than manually defining views + URLs?
2. Can you think of a project where auto-generated routes could save you lots of time?

Mini Exercise:

Create a ModelViewSet for one of your models.


Register it with a DefaultRouter and check if /modelname/ and /modelname/<id>/ work out of the box.

Do you want me to show you custom actions in ViewSets (like @action for special endpoints), or should
we move on to Module 4: URLs & Routing more deeply?

[Link] configuration
2.e comerce

Spot on again ✅
1. Less configuration — yes! ViewSets + Routers let you avoid repeating the same patterns for every
model. Instead of writing separate CRUD endpoints manually, you get them auto-wired.
2. E-commerce — perfect example. Imagine you have models like Product, Order, Cart, Review. Each
needs CRUD endpoints. With ViewSets + Routers, you can set them all up with just a few lines each.

Next Step Options


👉 We can now go into Custom Actions in ViewSets — where you add extra endpoints beyond CRUD
(e.g., ).
👉 Or, we can move forward into Module 4: URLs & Routing to see deeper routing patterns (like nested
/books/<id>/publish/

routes).

Which way would you like to go?

Customisation then move

Nice 👍 let’s customize ViewSets before moving to routing.


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 14/66
Lesson 3.5: Custom Actions in ViewSets
While ModelViewSet gives you CRUD out of the box, sometimes you need extra endpoints — for
example:

/books/<id>/publish/

/orders/<id>/cancel/

/products/<id>/discount/

DRF gives us the @action decorator for this.

1. Example: Detail Action (works on a single object)

python

from rest_framework.decorators import action


from rest_framework.response import Response

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
book = self.get_object()
[Link] = True
[Link]()
return Response({"status": f"Book '{[Link]}' published!"})

➡️ This gives you a new endpoint:


POST /books/<id>/publish/

2. Example: List Action (works on the collection)

python

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

@action(detail=False, methods=['get'])
def recent(self, request):
recent_books = [Link].order_by('-published_date')[:5]
serializer = self.get_serializer(recent_books, many=True)
return Response([Link])

➡️ This gives:
GET /books/recent/ → returns last 5 books.

3. Permissions on Actions

You can even add custom permissions just for specific actions:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 15/66
python

@action(detail=True, methods=['post'], permission_classes=[IsAdminUser])


def approve(self, request, pk=None):
book = self.get_object()
[Link] = True
[Link]()
return Response({"status": "Book approved by admin!"})

✅ Now ViewSets are not only CRUD — they’re extensible APIs.


Socratic Questions:

1. Why might it be better to create a custom action (/books/<id>/publish/) instead of trying to overload
the standard update endpoint?
2. Can you think of a custom action that would make sense in an e-commerce project (e.g., for Order or
Cart)?

Mini Exercise:

Add one custom action (@action) to your ViewSet — e.g., /products/<id>/apply_discount/ that
reduces the price.

Ready to move to Module 4: URLs & Routing (including nested routes), or do you want to experiment
with one more customization example before we move?

Explain explain terms like pk details and all other terms as I am not aware of them

Perfect 👌 — let’s slow down and make sure all the terms in ViewSets and actions are crystal clear.
🔑 Key Terms in DRF ViewSets & Actions
1. pk

Meaning: Primary Key (the unique ID for a row in the database).


Example: if your Book model has id=1 for "Django for Beginners," then:

GET /books/1/ → retrieves the book with id=1.


In the method signature:

python

def publish(self, request, pk=None):

pk is automatically captured from the URL (e.g., /books/1/publish/ → pk=1).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 16/66
2. detail=True vs detail=False in @action

detail=True → the action applies to a single object (needs a pk).

Example: POST /books/1/publish/


detail=False → the action applies to the entire collection.
Example: GET /books/recent/ (no pk needed).

3. queryset

The set of database objects your ViewSet works on.

Example:

python

queryset = [Link]()

means “this API works with all Book objects in the DB.”

4. serializer_class

The serializer used to translate model objects ↔ JSON.

Example:

python

serializer_class = BookSerializer

ensures all responses and requests go through that serializer.

5. get_object()

Inside a ViewSet, this fetches the specific object by its pk.


Example:

python

book = self.get_object()

If you called /books/5/publish/, this fetches the book with id=5.

6. Response

DRF’s special response object that ensures data is returned as JSON (not raw HTML).
Example:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 17/66
python

return Response({"status": "Book published!"})

7. methods=['get', 'post']

Defines which HTTP methods the custom action accepts.

Example:
methods=['get'] → use with GET

methods=['post'] → use with POST

8. permission_classes

Lets you restrict access to certain users/roles.


Example:

python

@action(detail=True, methods=['post'], permission_classes=[IsAdminUser])

means only admins can call this action.

✅ So in short:
pk = which object

detail=True = action on a single object


detail=False = action on the whole collection
queryset + serializer_class = what data and how it’s translated

get_object() = fetches the object by pk


Response = return JSON
methods = which HTTP verbs allowed

permission_classes = who is allowed

Quick Socratic Check:

1. If you want to approve just one order, should your custom action have detail=True or detail=False?
2. If you want an endpoint /orders/pending/ that returns all pending orders, would that be detail=True
or detail=False?

👉 Once you’re comfy with these, we’ll move to Module 4: URLs & Routing (including nested routes).

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 18/66
[Link]
[Link]

Exactly! ✅
1. Approve one order → detail=True because it acts on a single object.

2. List all pending orders → detail=False because it acts on the collection.

Perfect understanding of ViewSet terms! 🎯


Next, let’s move to Module 4: URLs & Routing, including nested routes and more advanced patterns.

Do you want me to start with basic routing with Routers, or go straight to nested/complex routing?

Yes

Great! Let’s start with basic routing with Routers first — this is the foundation before nested or
advanced routing.

Module 4: URLs & Routing – Lesson 4.1: Basic Routing


1. The Problem

Normally in Django, you write URLs like this:

python

from [Link] import path


from .views import BookListView, BookDetailView

urlpatterns = [
path('books/', BookListView.as_view(), name='book-list'),
path('books/<int:pk>/', BookDetailView.as_view(), name='book-detail'),
]

For every model, you repeat the same pattern (list, create, retrieve, update, delete).

2. The Solution: Routers

DRF routers auto-generate all standard CRUD URLs for a ViewSet.

Example with DefaultRouter:

python

from rest_framework.routers import DefaultRouter


from [Link] import path, include

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 19/66
from .views import BookViewSet

router = DefaultRouter()
[Link](r'books', BookViewSet)

urlpatterns = [
path('', include([Link])),
]

3. What the Router Generates

Assuming BookViewSet is a ModelViewSet:

URL HTTP Method Action


/books/ GET list
/books/ POST create
/books/<pk>/ GET retrieve

/books/<pk>/ PUT update


/books/<pk>/ PATCH partial update
/books/<pk>/ DELETE destroy

No need to manually write each URL.

4. Using Routers with Custom Actions

Custom actions (@action) are automatically added to the router.


Example:

python

@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
# This creates /books/<pk>/publish/

Socratic Questions:

1. Why are routers considered a “time saver” in large projects with many models?
2. If you didn’t use routers, what would you need to do for every new model in your API?

Mini Exercise:

Take one of your models, create a ModelViewSet, register it with a DefaultRouter, and test all CRUD
endpoints using Postman or browser.

Do you want me to now cover nested routes (e.g., /authors/<author_id>/books/) for relationships
between models?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 20/66
Yes

Perfect! Let’s dive into nested routes — very useful when you have related models, like authors and
their books, or orders and order items.

Lesson 4.2: Nested Routing


1. The Problem

Suppose you have these models:

python

class Author([Link]):
name = [Link](max_length=100)

class Book([Link]):
title = [Link](max_length=100)
author = [Link](Author, on_delete=[Link])

You want endpoints like:


/authors/ → list authors

/authors/<id>/books/ → list books for a specific author

Manually doing this with standard URLs is cumbersome.

2. The Solution: drf-nested-routers

Install it first:

bash

pip install drf-nested-routers

Setup nested routers:

python

from rest_framework_nested import routers


from [Link] import path, include
from .views import AuthorViewSet, BookViewSet

router = [Link]()
[Link](r'authors', AuthorViewSet)

# Nested router for books under authors


authors_router = [Link](router, r'authors', lookup='author')
authors_router.register(r'books', BookViewSet, basename='author-books')

urlpatterns = [
path('', include([Link])),
path('', include(authors_router.urls)),
]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 21/66
3. How it Works

lookup='author' → tells DRF to expect author_pk in the URL


Generated endpoints:

URL HTTP Method Action

/authors/ GET list authors


/authors/<pk>/ GET retrieve author
/authors/<author_pk>/books/ GET list books for this author

/authors/<author_pk>/books/<pk>/ GET retrieve a specific book for this author

In your BookViewSet, you can access author_pk:

python

def get_queryset(self):
return [Link](author_id=[Link]['author_pk'])

4. Why Nested Routes Are Useful

Makes relationships explicit in the URL.

Easy for clients to understand hierarchy (author -> books, order -> items).
Helps organize permissions: you can restrict access to only a parent’s related objects.

Socratic Questions:

1. Why might /authors/<id>/books/ be better than /books/?author=<id> for some APIs?


2. How would you access the author_pk inside a BookViewSet method to filter results?

Mini Exercise:

Try creating a nested route for two related models in your project.
Implement get_queryset in the child ViewSet to filter by the parent’s pk.

Once you’re comfortable with nested routes, the next big step is Authentication & Permissions, which
secures your APIs.
Do you want me to move to that next?

1. It is easy to find the authors and its books compared to all books then find the author
2.

Exactly! ✅
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 22/66
1. Correct — /authors/<id>/books/ makes it clear and intuitive which books belong to which author,
instead of fetching all books and filtering manually.
2. Accessing author_pk inside BookViewSet:

DRF passes URL parameters into [Link] automatically.


Example:

python

def get_queryset(self):
author_id = [Link]['author_pk'] # author_pk comes from the nested router
return [Link](author_id=author_id)

Now your queryset automatically returns only books for that author.

✅ You now understand nested routes, parent-child relationships in APIs, and how to filter child objects
properly.

The next logical module is Module 5: Authentication & Permissions — securing your API so only
allowed users can access or modify data.
Shall we move to Auth & Permissions?

def get_queryset(self):
author_id = [Link]['author_pk'] # author_pk comes from the nested router
return [Link](author_id=author_id)

Explain with full example then move

Absolutely! Let’s go step by step and create a complete example for nested routing with Author and Book
models using DRF.

Full Example: Nested Routing


1. Models

python

from [Link] import models

class Author([Link]):
name = [Link](max_length=100)

def __str__(self):
return [Link]

class Book([Link]):
title = [Link](max_length=100)
author = [Link](Author, on_delete=[Link])

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 23/66
def __str__(self):
return [Link]

2. Serializers

python

from rest_framework import serializers


from .models import Author, Book

class AuthorSerializer([Link]):
class Meta:
model = Author
fields = '__all__'

class BookSerializer([Link]):
class Meta:
model = Book
fields = '__all__'

3. ViewSets

python

from rest_framework import viewsets


from .models import Author, Book
from .serializers import AuthorSerializer, BookSerializer

class AuthorViewSet([Link]):
queryset = [Link]()
serializer_class = AuthorSerializer

class BookViewSet([Link]):
serializer_class = BookSerializer

def get_queryset(self):
# 'author_pk' comes from the nested router
author_id = [Link]['author_pk']
return [Link](author_id=author_id)

def perform_create(self, serializer):


# Automatically associate the book with the author
author_id = [Link]['author_pk']
[Link](author_id=author_id)

4. Routers (Nested)

python

from rest_framework_nested import routers


from [Link] import path, include
from .views import AuthorViewSet, BookViewSet

# Main router
router = [Link]()
[Link](r'authors', AuthorViewSet)

# Nested router for books under authors


authors_router = [Link](router, r'authors', lookup='author')
authors_router.register(r'books', BookViewSet, basename='author-books')

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 24/66
urlpatterns = [
path('', include([Link])),
path('', include(authors_router.urls)),
]

5. How it Works

/authors/ → list all authors

/authors/<author_pk>/ → retrieve one author


/authors/<author_pk>/books/ → list books for that author
/authors/<author_pk>/books/<pk>/ → retrieve, update, delete a specific book

Inside BookViewSet:

[Link]['author_pk'] fetches the parent author’s ID from the URL.

get_queryset() filters books by that author.


perform_create() ensures new books are automatically linked to the correct author.

Example Usage

If author with ID 3 exists:


GET /authors/3/books/ → returns only books where author_id=3

POST /authors/3/books/ → creates a book linked to author 3

This is the full nested routing pattern in DRF, showing how get_queryset uses [Link]['author_pk']
to filter child objects automatically.

Next, we can move to Module 5: Authentication & Permissions to secure the API so only authorized
users can create, edit, or delete data.

Do you want me to move to Auth & Permissions now?

Now tell which API view is used generally which is best give a table and what is the most
industries

Perfect! Let’s summarize all the common DRF API views and their typical usage in industry. I’ll make a
clear table for comparison.

DRF API Views Comparison

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 25/66
View Type Description Pros Cons Industry
Easy to Small projects,
Function-Based Simple Python functions decorated Repetitive for CRUD,
understand, prototypes, mi
View (FBV) with @api_view harder to scale
very explicit endpoints
Reusable,
organized,
Class-Based View OOP-style views with get, post, better for Still boilerplate for Medium projec
(APIView) etc. methods medium- CRUD endpoints
sized
projects
Minimal
boilerplate,
Pre-built classes like Most CRUD AP
handles Less flexible for very
Generic Views ListCreateAPIView, industry, medi
common custom logic
RetrieveUpdateDestroyAPIView apps
CRUD
automatically
Very clean,
Can feel “magic” for
auto-CRUD, Most common
Combines all CRUD in one class beginners,
ViewSets works industry APIs
(ModelViewSet) sometimes less
seamlessly commerce, Saa
granular control
with Routers
Good for
ViewSet that only allows list and Cannot
ReadOnlyViewSet public APIs, Public data AP
retrieve create/update/delete
very simple
Flexible,
Custom ViewSet / powerful, Industry APIs w
Extends ViewSet with custom Slightly more
Generic + integrates actions (e.g.,
endpoints complex
@action well with /orders/<id>
Routers

Industry Patterns

1. Small projects / prototypes → FBV or APIView (explicit & simple)


2. Medium CRUD-heavy apps → Generic Views

3. Large-scale apps / production-ready APIs → ModelViewSet + Routers + Custom Actions


Examples:
E-commerce (ProductViewSet, OrderViewSet)
SaaS apps (users, subscriptions)
Social networks (posts, comments)
4. Public read-only APIs → ReadOnlyViewSet

✅ Bottom line:
Most industry APIs use ModelViewSet + Routers for standard CRUD.
Custom actions are added where business logic requires special endpoints.
This pattern minimizes boilerplate, enforces consistency, and scales well.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 26/66
If you want, I can also draw a visual “decision tree” showing which DRF view to choose for which
situation, so you can pick quickly when designing APIs.
Do you want me to make that visual?

Now move

Perfect! Now that we’ve covered Views, ViewSets, and Routing, the next essential module is Module 5:
Authentication & Permissions — this ensures only the right users can access or modify your APIs.

Module 5: Authentication & Permissions – Lesson 5.1: Basics


1. Authentication vs Permissions

Authentication → Who is the user? (Are they logged in? Identity verification)
Permission → What is the user allowed to do? (Can they view, edit, delete this resource?)

Think of it like:

Authentication = “Who are you?”


Permission = “What can you do?”

2. Common Authentication Methods in DRF

Method How it works Use case


Websites with DRF endpoints, admin
SessionAuth Uses Django’s normal login sessions
apps
Users get a token on login; token sent with API
TokenAuth Mobile apps, simple APIs
requests

JWT (JSON Web Signed JWT token sent with requests, no Modern web apps, SPA, mobile apps,
Token) server-side session scalable APIs
OAuth2 Third-party authorization & authentication Social login, enterprise APIs

3. Common Permission Classes

Permission What it does

AllowAny Anyone can access


IsAuthenticated Only logged-in users
IsAdminUser Only admin users
IsAuthenticatedOrReadOnly Authenticated users can write, everyone can read

4. Example: Token Authentication + Permission

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 27/66
python

from rest_framework.authentication import TokenAuthentication


from rest_framework.permissions import IsAuthenticated
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]

Only users with a valid token can access these endpoints.

Socratic Questions:

1. Why might you want IsAuthenticatedOrReadOnly for a public blog API?

2. Why is JWT preferred for mobile apps over traditional session authentication?

Mini Exercise:

Protect one of your ViewSets with IsAuthenticated and test with/without login credentials.

Do you want me to move into JWT authentication setup next, which is very common in industry APIs?

Yes

Perfect! Let’s cover JWT (JSON Web Token) Authentication — widely used in modern industry APIs for
web and mobile apps.

Module 5: Authentication & Permissions – Lesson 5.2: JWT


1. What is JWT?

JWT is a compact, URL-safe token that proves the identity of a user.


It contains three parts: Header, Payload, Signature
Header → algorithm info (e.g., HS256)

Payload → user info & claims


Signature → ensures token wasn’t tampered
Client stores the JWT and sends it with each API request in the Authorization header:

makefile

Authorization: Bearer <your_jwt_token>

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 28/66
2. Why JWT over Session/Token?

Stateless → server doesn’t store session info


Works across domains & mobile apps easily
Scalable for distributed systems

3. Setup in Django REST Framework

Install package:

bash

pip install djangorestframework-simplejwt

Add to [Link]:

python

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.[Link]',
)
}

4. URLs for JWT

python

from [Link] import path


from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

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

/api/token/ → POST username/password, get access & refresh tokens


/api/token/refresh/ → POST refresh token to get a new access token

5. Protecting ViewSets

python

from rest_framework.permissions import IsAuthenticated


from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 29/66
serializer_class = BookSerializer
permission_classes = [IsAuthenticated] # only logged-in users

Requests must include JWT in header:

makefile

Authorization: Bearer <access_token>

Socratic Questions:

1. Why is a refresh token needed in addition to the access token?


2. How does JWT being stateless make APIs more scalable?

Mini Exercise:

Protect a ViewSet with JWT authentication


Test logging in to get a token, and use it to access the API with Postman or HTTP client

Do you want me to move next to custom permissions and object-level permissions, which are critical
in real-world apps?

Answer questions then custom

Perfect! Let’s tackle the questions first.

Question 1: Why is a refresh token needed?

Answer:
Access tokens are usually short-lived for security (e.g., 5–15 minutes).
When the access token expires, the user would normally have to log in again.
The refresh token is long-lived and can be exchanged for a new access token without asking
the user to log in again.
This improves security (short-lived access) while keeping the experience smooth (user stays
logged in).

Question 2: How does JWT being stateless make APIs more scalable?

Answer:
JWT does not require server-side session storage.
Each request contains all the information needed to authenticate the user.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 30/66
This means:
You can scale horizontally across many servers without sharing session data.
No database or cache lookup for session validation is needed per request.
Perfect for microservices, cloud deployments, and mobile apps.

✅ Now that’s clear, let’s move to custom permissions and object-level permissions — very important
in real-world apps.

Module 5.3: Custom & Object-Level Permissions


1. Why Custom Permissions?

Built-in permissions like IsAuthenticated or IsAdminUser are coarse-grained.

Sometimes you want specific rules, e.g.:


Only the author of a blog post can edit/delete it.
Only managers can approve orders.

2. Creating a Custom Permission

python

from rest_framework import permissions

class IsOwnerOrReadOnly([Link]):
"""
Object-level permission: only the owner can edit; others can read.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request
if [Link] in permissions.SAFE_METHODS:
return True
# Write permissions only for owner
return [Link] == [Link]

3. Using the Custom Permission in a ViewSet

python

from rest_framework import viewsets


from .models import Book
from .serializers import BookSerializer
from .permissions import IsOwnerOrReadOnly

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
permission_classes = [IsOwnerOrReadOnly] # apply custom permission

Now:

GET /books/ → everyone can read


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 31/66
PUT /books/1/ → only the owner of book 1 can update
DELETE /books/1/ → only the owner can delete

Socratic Questions:

1. Why is object-level permission better than just IsAuthenticated for some APIs?

2. Can you think of a real-world example in e-commerce where object-level permission is needed?

Mini Exercise:

Write a custom permission for your model where only the creator can update/delete.
Apply it to a ViewSet and test with multiple users.

Do you want me to move next to throttling & rate limiting, which is another critical security and
performance layer in DRF?

1. It is not like that if the user is logged in than he can change delete the book of any other user
2. Adding the product and card if I am logged in so only I can add product to my order cart only
not to the other carts

Exactly! ✅
1. Correct — using just IsAuthenticated would let any logged-in user modify any object, which is
usually not what we want. Object-level permissions ensure users can only modify their own data.
2. Perfect e-commerce example — each user should only be able to add products to their own cart,
not other users’ carts. Object-level permissions enforce that automatically.

Next, let’s move to Module 6: Throttling & Rate Limiting — important for protecting your API from
abuse and controlling traffic.

Do you want me to explain basic throttling first or jump straight into custom throttling per
user/action?

Basic throttling first

Perfect! Let’s start with basic throttling in Django REST Framework.

Module 6: Throttling & Rate Limiting – Lesson 6.1: Basic


Throttling
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 32/66
1. What is Throttling?

Throttling = limiting how many requests a client can make to your API in a given time period.
Helps prevent:
API abuse (spam requests)
Server overload

Denial-of-service attacks

2. Built-in Throttle Classes in DRF

Throttle Class Description


AnonRateThrottle Limits unauthenticated users
UserRateThrottle Limits authenticated users

ScopedRateThrottle Limits based on scope defined per view

3. Setting Throttling Globally

In [Link]:

python

REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.[Link]',
'rest_framework.[Link]',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '10/min', # 10 requests per minute for anonymous users
'user': '100/min', # 100 requests per minute for authenticated users
}
}

Now all API endpoints will be throttled globally according to these rates.

4. Throttling Per View

You can also set throttling per ViewSet:

python

from rest_framework.throttling import UserRateThrottle, AnonRateThrottle


from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
throttle_classes = [UserRateThrottle, AnonRateThrottle]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 33/66
5. What Happens When Limit is Reached

DRF automatically returns HTTP 429 Too Many Requests

json

{
"detail": "Request was throttled. Expected available in 60 seconds."
}

Socratic Questions:

1. Why is it useful to throttle anonymous users differently from authenticated users?


2. Can you think of an endpoint in e-commerce where throttling is especially important?

Mini Exercise:

Set up AnonRateThrottle to allow only 5 requests per minute to your public API.
Test hitting the endpoint multiple times and observe the 429 response.

Do you want me to now cover custom throttling, like limiting specific users or actions differently?

Yes

Perfect! Let’s dive into custom throttling in DRF, which lets you create fine-grained limits per user,
endpoint, or action.

Module 6.2: Custom Throttling


1. Why Custom Throttling?

Default throttles (like UserRateThrottle) are global per user.


In real-world apps, you may want:
Higher limits for premium users

Lower limits for free users


Separate limits for heavy actions like /checkout/ vs. /view-products/

2. Creating a Custom Throttle

python

from rest_framework.throttling import SimpleRateThrottle

class PremiumUserThrottle(SimpleRateThrottle):
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 34/66
scope = 'premium_user'

def get_cache_key(self, request, view):


# Only throttle authenticated users
if not [Link].is_authenticated:
return None

# Example: premium users have higher limits


if [Link].is_premium:
return None # no throttling for premium users

# Use user ID as key


return f"user-{[Link]}"

3. Registering Custom Throttle Rates

In [Link]:

python

REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'[Link]',
],
'DEFAULT_THROTTLE_RATES': {
'premium_user': '50/min', # 50 requests/min for non-premium users
}
}

4. Applying Custom Throttle Per View

python

from rest_framework import viewsets


from .models import Order
from .serializers import OrderSerializer
from .throttles import PremiumUserThrottle

class OrderViewSet([Link]):
queryset = [Link]()
serializer_class = OrderSerializer
throttle_classes = [PremiumUserThrottle]

Now, free users are limited to 50 requests per minute for orders, but premium users are
unthrottled.

5. Advanced Customization

You can base throttling on:


User groups
Subscription type
Action (create, update)
IP address

Example: throttle only checkout requests:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 35/66
python

def get_cache_key(self, request, view):


if [Link] != 'checkout':
return None
return f"user-{[Link]}"

Socratic Questions:

1. Why would throttling only the checkout action be more efficient than throttling all endpoints?
2. How could custom throttling improve user experience for premium vs free users?

Mini Exercise:

Create a custom throttle that limits non-premium users to 10 cart additions per hour, but allows
premium users unlimited access.
Apply it to your CartViewSet and test.

Do you want me to move next to Pagination, which is also critical for performance in industry APIs?

Yes

Perfect! Let’s move to Module 7: Pagination — crucial for efficiently handling large datasets in APIs.

Module 7: Pagination – Lesson 7.1: Basics


1. What is Pagination?

Pagination = splitting large query results into smaller, manageable chunks.


Helps:
Reduce server load
Improve client performance
Avoid sending thousands of records at once

2. DRF Built-in Pagination Classes

Class Description
PageNumberPagination Standard page numbers (?page=2)
LimitOffsetPagination Specify limit & offset (?limit=10&offset=20)
CursorPagination Cursor-based pagination, efficient for large datasets

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 36/66
3. Setup Global Pagination

In [Link]:

python

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.[Link]',
'PAGE_SIZE': 10, # 10 items per page
}

Now all list endpoints automatically return 10 items per page.

4. Example Response

json

{
"count": 105,
"next": "[Link]
"previous": null,
"results": [
{"id": 1, "title": "Book 1", "author": 1},
{"id": 2, "title": "Book 2", "author": 2},
...
]
}

count = total items


next / previous = pagination links
results = items on current page

5. Pagination Per View

python

from rest_framework.pagination import PageNumberPagination


from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookPagination(PageNumberPagination):
page_size = 5 # override global setting
page_size_query_param = 'page_size' # allow client to set size

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
pagination_class = BookPagination

Client can now request different page sizes:

bash

GET /books/?page=1&page_size=3

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 37/66
Socratic Questions:

1. Why is pagination important for endpoints that return thousands of records?


2. When would you prefer cursor-based pagination over page-number pagination?

Mini Exercise:

Implement PageNumberPagination for your ProductViewSet or BookViewSet.


Test fetching multiple pages with ?page=1, ?page=2 etc.

Do you want me to next cover LimitOffsetPagination and CursorPagination, which are commonly
used in real-world high-scale APIs?

Yes

Perfect! Let’s cover LimitOffsetPagination and CursorPagination, which are more advanced and often
used in large-scale production APIs.

Module 7.2: Advanced Pagination


1. LimitOffsetPagination

Instead of pages, you control how many items and where to start.
Example URL:

pgsql

GET /books/?limit=10&offset=20

limit=10 → return 10 items


offset=20 → skip first 20 items
Useful when clients want custom slices of data.

Setup in DRF:

python

from rest_framework.pagination import LimitOffsetPagination


from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5
max_limit = 50

class BookViewSet([Link]):
queryset = [Link]()

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 38/66
serializer_class = BookSerializer
pagination_class = BookLimitOffsetPagination

2. CursorPagination

Cursor-based pagination uses a unique cursor (usually ID or timestamp) instead of page numbers.

Pros:
Efficient for large datasets
Works well with constantly changing data (no duplicates or skipped items)
Example URL:

sql

GET /books/?cursor=YXJyYXljb25uZWN0aW9uOjEw

Setup in DRF:

python

from rest_framework.pagination import CursorPagination

class BookCursorPagination(CursorPagination):
page_size = 5
ordering = 'published_date' # cursor orders by this field

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
pagination_class = BookCursorPagination

next and previous links are automatically generated with cursor values.

3. When to Use Each

Pagination Type Best Use Case


PageNumberPagination Small to medium datasets, simple APIs
LimitOffsetPagination APIs that allow flexible slicing
CursorPagination Large datasets, constantly changing data, avoid duplicates

Socratic Questions:

1. Why might page-number pagination fail when new records are added during pagination?
2. Why is cursor pagination safer for APIs with millions of records?

Mini Exercise:

Implement CursorPagination on your BookViewSet or ProductViewSet.

Test fetching next/previous pages and observe how the cursor works.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 39/66
Next, we can move to Filtering & Search, which is critical in industry APIs for letting clients query
efficiently.
Do you want me to move to Filtering & Search?

First answer questions then move

Absolutely! Let’s answer the questions first.

Question 1: Why might page-number pagination fail when new records are added
during pagination?

Answer:
Page-number pagination relies on fixed page numbers.
If new records are added to the dataset while a client is paginating:
Items may shift between pages
The client could see duplicates or skip items

Example: If page 1 had items 1–10, and a new item is added at the start, page 2 might now
skip the old item 11 or show duplicates.

Question 2: Why is cursor pagination safer for APIs with millions of records?

Answer:
Cursor pagination uses a unique, stable value (like ID or timestamp) to navigate.

It doesn’t depend on page numbers, so new records won’t disrupt pagination.


It’s more efficient for large datasets because the database can quickly fetch rows after the
cursor without counting or offsetting large numbers of rows.

✅ With that clear, let’s move to Module 8: Filtering & Search — essential for letting clients query
efficiently, like /books/?author=1&title=django.
Do you want me to start with basic filtering first or jump straight to advanced search with
DjangoFilterBackend and search fields?

Give example and calculate the number for the diff pagination to explain then move

Perfect! Let’s make a concrete example with numbers to see how each pagination type behaves.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 40/66
Example Dataset
Assume we have 105 books in our database, each with a unique id from 1 to 105.

1. PageNumberPagination

PAGE_SIZE = 10

Total pages: ceil(105 / 10) = 11 pages

Page Items (IDs)


1 1–10
2 11–20

3 21–30
... ...
11 101–105

Pros: Easy to understand


Cons: If new books are added while a client is paging, items shift pages, causing duplicates or skipped
items.

2. LimitOffsetPagination

Example: limit=10
Fetch requests:
/books/?limit=10&offset=0 → IDs 1–10
/books/?limit=10&offset=10 → IDs 11–20
/books/?limit=10&offset=100 → IDs 101–105

Pros: Clients can skip or fetch any slice


Cons: Like page-number pagination, inserting new records at the beginning can shift offsets and cause
duplicates or skips.

3. CursorPagination

Using ordering='id' and page_size=10


Fetch requests:
/books/?cursor=<start> → first 10 items (1–10)
/books/?cursor=<next> → next 10 items (11–20)
/books/?cursor=<next> → next 10 items (21–30), etc.

Pros:

Even if new books are inserted at the start, the cursor ensures no duplicates or skipped items

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 41/66
Very efficient for large datasets because it doesn’t use OFFSET in SQL

Summary Table

Page 1 Page 11 Issue with New Performance for Millions of


Pagination Type
Items Items Records? Records
PageNumberPagination 1–10 101–105 Yes, items can shift Slower, uses OFFSET
LimitOffsetPagination 1–10 101–105 Yes, items can shift Slower, uses OFFSET
CursorPagination 1–10 101–105 No, stable Fast, efficient

This numerical example shows why cursor pagination is preferred for large, constantly changing
datasets in industry APIs.

Next, we can move to Filtering & Search, which is essential to let clients query APIs efficiently.
Do you want me to start with basic filtering first?

Yes

Perfect! Let’s start with basic filtering in DRF.

Module 8: Filtering & Search – Lesson 8.1: Basic Filtering


1. What is Filtering?

Filtering = letting clients request a subset of data based on field values.


Example: /books/?author=3 → only books by author with ID 3

2. Simple Filtering with Query Parameters

python

from rest_framework import viewsets


from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

def get_queryset(self):
queryset = super().get_queryset()
author_id = [Link].query_params.get('author')
if author_id:
queryset = [Link](author_id=author_id)
return queryset

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 42/66
Client requests:

bash

GET /books/?author=3
GET /books/?title=Django

Pros: Very flexible for small APIs


Cons: Becomes messy for multiple fields or complex filtering

3. Using DjangoFilterBackend (Industry Standard)

Install package:

bash

pip install django-filter

Add to [Link]:

python

REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

Update ViewSet:

python

from django_filters.rest_framework import DjangoFilterBackend

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'title'] # fields clients can filter

Client requests:

bash

GET /books/?author=3
GET /books/?title=Django
GET /books/?author=3&title=Django

Automatically filters without writing custom get_queryset() logic.

4. Socratic Questions

1. Why is DjangoFilterBackend preferred in large production APIs over manually filtering in


get_queryset()?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 43/66
2. How would you allow filtering books by price range or publication date?

Mini Exercise:

Add price and published_date filters to your BookViewSet

Test queries like:

bash

GET /books/?price__gte=100&price__lte=500
GET /books/?published_date__year=2023

Do you want me to move next to Search and Ordering, which often goes hand-in-hand with filtering in
industry APIs?

1. No manual handling
2.

Exactly! ✅
1. Correct — using DjangoFilterBackend avoids manual filtering in get_queryset(), making your code
cleaner, more maintainable, and scalable.
2. Filtering by range or dates:

DjangoFilterBackend supports lookup expressions, e.g.:

python

filterset_fields = {
'price': ['exact', 'gte', 'lte'], # exact, greater than or equal, less than or
equal
'published_date': ['exact', 'year', 'month'] # filter by year/month
}

Example queries:

bash

GET /books/?price__gte=100&price__lte=500
GET /books/?published_date__year=2023

Next, let’s move to Search and Ordering, which are widely used in industry APIs for keyword search
and sorting.
Do you want me to cover Search first or Ordering first?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 44/66
What ever

Let’s start with Search, then we’ll cover Ordering—both are critical for making APIs user-friendly in real-
world apps.

Module 8.2: Search and Ordering


1. Search

Allows clients to search by keywords in one or more fields.


Example: /books/?search=django → returns books where title or description contains “django”.

Setup:

python

from rest_framework import viewsets, filters


from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
filter_backends = [[Link]]
search_fields = ['title', 'description'] # fields to search

Example client requests:

sql

GET /books/?search=python
GET /books/?search=django

Notes:

Uses icontains lookup by default → case-insensitive partial match


Works well for small to medium datasets

2. Ordering

Lets clients sort results by one or more fields.


Example: /books/?ordering=price → ascending price
Example: /books/?ordering=-price → descending price

Setup:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 45/66
python

from rest_framework import filters

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
filter_backends = [[Link]]
ordering_fields = ['price', 'published_date'] # fields clients can sort
ordering = ['published_date'] # default ordering

Example requests:

bash

GET /books/?ordering=price
GET /books/?ordering=-published_date

3. Combining Search, Ordering, and Filtering

python

from django_filters.rest_framework import DjangoFilterBackend


from rest_framework import filters

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend, [Link], [Link]]
filterset_fields = ['author', 'price']
search_fields = ['title', 'description']
ordering_fields = ['price', 'published_date']
ordering = ['published_date']

Clients can now do:

sql

GET /books/?author=3&search=django&ordering=-price

This is exactly how large industry APIs handle querying — clean, powerful, and scalable.

Socratic Questions:

1. Why is combining filtering, search, and ordering important in large production APIs?
2. What could go wrong if search and ordering are not restricted to certain fields?

Mini Exercise:

Implement filtering, search, and ordering for your ProductViewSet or BookViewSet.


Test queries like:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 46/66
sql

GET /books/?author=2&search=python&ordering=-price
GET /books/?price__gte=100&search=django&ordering=published_date

Do you want me to move next to Serializer Relationships, which is key for nested and related data in
DRF?

[Link] to large data and personalization


2.

Exactly! ✅
1. Correct — combining filtering, search, and ordering allows clients to efficiently find relevant data
in large datasets and supports personalized results (e.g., recommended books, user-specific
products).
2. Potential issue if unrestricted search/ordering:

Clients could query any field, including sensitive ones, which may leak data.
Performance problems: sorting large datasets on unindexed fields can slow down the API.
Solution: always restrict search and ordering to specific fields.

Next, let’s move to Module 9: Serializer Relationships — crucial for handling nested data and related
models, like authors and their books, orders and order items.
Do you want me to start with basic ForeignKey/One-to-Many relationships first?

Yes

Perfect! Let’s start with basic serializer relationships in DRF.

Module 9: Serializer Relationships – Lesson 9.1: ForeignKey / One-


to-Many
1. Scenario

We have two models: Author and Book


Each book belongs to one author → ForeignKey relationship

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 47/66
python

class Author([Link]):
name = [Link](max_length=100)

class Book([Link]):
title = [Link](max_length=100)
author = [Link](Author, on_delete=[Link])

2. Basic Serializer Representation

python

from rest_framework import serializers


from .models import Author, Book

class BookSerializer([Link]):
class Meta:
model = Book
fields = ['id', 'title', 'author'] # 'author' is just the ID

Example API response:

json

{
"id": 1,
"title": "Django for Beginners",
"author": 3 # author ID only
}

Simple, but not human-readable if you want author details.

3. Nested Serializer

To show author details instead of just ID:

python

class AuthorSerializer([Link]):
class Meta:
model = Author
fields = ['id', 'name']

class BookSerializer([Link]):
author = AuthorSerializer(read_only=True) # nested author info

class Meta:
model = Book
fields = ['id', 'title', 'author']

API response now:

json

{
"id": 1,
"title": "Django for Beginners",
Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 48/66
"author": {
"id": 3,
"name": "John Doe"
}
}

4. Writable Nested Relationships (Optional)

If you want to create a book with an author ID:

python

class BookSerializer([Link]):
class Meta:
model = Book
fields = ['id', 'title', 'author'] # 'author' can be written as ID

POST /books/ payload:

json

{
"title": "Advanced Django",
"author": 3
}

Socratic Questions:

1. When would you prefer nested serializer over just an ID?


2. What are potential downsides of nesting too many levels in serializers?

Mini Exercise:

Implement BookSerializer with nested AuthorSerializer.


Fetch a list of books and verify the author details appear inside each book.

Do you want me to move next to Many-to-Many relationships in serializers, like books and
tags/categories?

Answer then move

Absolutely! Let’s answer the questions first.

Question 1: When would you prefer nested serializer over just an ID?

Answer:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 49/66
When you want the API response to include readable, meaningful data for clients without
requiring extra requests.
Example: In a book API, instead of returning just author_id=3, you return the author’s name and
other details.
Improves client convenience and reduces API calls.

Question 2: What are potential downsides of nesting too many levels in serializers?

Answer:
Performance issues: each nested level can trigger additional queries (N+1 problem).
Large responses: deeply nested data increases payload size.
Complexity: harder to maintain or update serializers.
Solution: Use select_related / prefetch_related and limit nesting depth.

✅ With that clear, let’s move to Many-to-Many relationships, which are common in real-world apps
like books and tags, products and categories.
Do you want me to start with basic read-only Many-to-Many or writable Many-to-Many?

Yes

Great! Let’s cover Many-to-Many relationships in serializers, starting with the basics.

Module 9.2: Many-to-Many Relationships


1. Scenario

Models: Book and Tag


Each book can have multiple tags, and each tag can belong to multiple books.

python

class Tag([Link]):
name = [Link](max_length=50)

class Book([Link]):
title = [Link](max_length=100)
tags = [Link](Tag, related_name='books')

2. Basic Read-Only Many-to-Many Serializer

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 50/66
python

from rest_framework import serializers

class TagSerializer([Link]):
class Meta:
model = Tag
fields = ['id', 'name']

class BookSerializer([Link]):
tags = TagSerializer(many=True, read_only=True) # nested tags

class Meta:
model = Book
fields = ['id', 'title', 'tags']

Example response:

json

{
"id": 1,
"title": "Django for Beginners",
"tags": [
{"id": 1, "name": "Programming"},
{"id": 2, "name": "Web"}
]
}

3. Writable Many-to-Many

If you want to create or update tags along with a book:

python

class BookSerializer([Link]):
tags = [Link](
many=True,
queryset=[Link]()
)

class Meta:
model = Book
fields = ['id', 'title', 'tags']

POST /books/ payload:

json

{
"title": "Advanced Django",
"tags": [1, 2]
}

DRF automatically handles the many-to-many assignment.

Socratic Questions:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 51/66
1. Why might you use PrimaryKeyRelatedField instead of nested serializers for writable relationships?
2. What are potential challenges when nesting many-to-many relationships too deeply?

Mini Exercise:

Implement BookSerializer with writable many-to-many for tags.


Test creating a book with multiple tags via API.

Do you want me to move next to Hyperlinked Relationships, which are common in RESTful APIs to
reduce payload size and make APIs more navigable?

Answer then move

Absolutely! Let’s answer the questions first.

Question 1: Why might you use PrimaryKeyRelatedField instead of nested


serializers for writable relationships?

Answer:
Using PrimaryKeyRelatedField avoids sending full nested objects when creating or updating a
resource.
It keeps payloads smaller and simplifies write operations.
Example: Instead of sending full tag objects, you just send their IDs:

json

{"title": "Advanced Django", "tags": [1, 2]}

Question 2: What are potential challenges when nesting many-to-many


relationships too deeply?

Answer:
Performance issues: Each nested level can trigger additional queries (N+1 problem).
Large response size: More data is sent over the network, slowing clients.
Complexity: Serializers become harder to maintain.
Solution: Limit nesting depth, use select_related / prefetch_related, or provide hyperlinked
relationships.

✅ With that clear, let’s move to Hyperlinked Relationships, which are widely used in RESTful APIs to
reduce payload size and make resources easier to navigate.

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 52/66
Do you want me to start with basic HyperlinkedModelSerializer?

Yes

Perfect! Let’s cover Hyperlinked Relationships in DRF.

Module 9.3: Hyperlinked Relationships


1. What is Hyperlinked Relationships?

Instead of embedding related objects, return URLs pointing to the related resource.
Reduces payload size and follows RESTful principles.

Example:

json

{
"id": 1,
"title": "Django for Beginners",
"author": "[Link]
}

2. HyperlinkedModelSerializer

DRF provides HyperlinkedModelSerializer to make this easy.

python

from rest_framework import serializers


from .models import Author, Book

class BookSerializer([Link]):
class Meta:
model = Book
fields = ['url', 'id', 'title', 'author']
extra_kwargs = {
'url': {'view_name': 'book-detail', 'lookup_field': 'pk'},
'author': {'view_name': 'author-detail', 'lookup_field': 'pk'}
}

Note:
url field points to the book’s detail API
author field points to the author’s detail API
API response:

json

{
"url": "[Link]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 53/66
"id": 1,
"title": "Django for Beginners",
"author": "[Link]
}

3. ViewSet Example

python

from rest_framework import viewsets


from .models import Book, Author
from .serializers import BookSerializer, AuthorSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

class AuthorViewSet([Link]):
queryset = [Link]()
serializer_class = AuthorSerializer

Ensure your routers are set correctly in [Link] for hyperlinked fields to resolve URLs.

Socratic Questions:

1. Why might hyperlinked relationships be preferred over nested serializers for large datasets?
2. What could be a downside of hyperlinked relationships for API clients?

Mini Exercise:

Convert your BookSerializer to HyperlinkedModelSerializer.


Fetch a book and verify that the author is represented as a URL.

Do you want me to move next to ViewSet actions and custom actions, which are essential for
extending API behavior?

Move

Perfect! Let’s move to Module 10: ViewSet Actions & Custom Actions, which are essential for
extending API behavior beyond standard CRUD.

Module 10: ViewSet Actions & Custom Actions


1. Standard ViewSet Actions

DRF’s ModelViewSet provides built-in actions:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 54/66
Action HTTP Method URL Example Description
list GET /books/ List all books
retrieve GET /books/1/ Get single book details
create POST /books/ Create new book
update PUT /books/1/ Update book
partial_update PATCH /books/1/ Partial update
destroy DELETE /books/1/ Delete book

These actions cover most CRUD operations.

2. Custom Actions

Sometimes, you need extra endpoints that don’t fit CRUD, e.g., /books/1/publish/.
Use @action decorator in ViewSets.

python

from rest_framework.decorators import action


from rest_framework.response import Response
from rest_framework import viewsets, status
from .models import Book
from .serializers import BookSerializer

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
book = self.get_object()
[Link] = True
[Link]()
return Response({'status': 'book published'}, status=status.HTTP_200_OK)

URL generated: /books/1/publish/

Method: POST

3. Custom Action for List

You can also add list-level custom actions:

python

@action(detail=False, methods=['get'])
def recent(self, request):
recent_books = [Link].order_by('-published_date')[:5]
serializer = self.get_serializer(recent_books, many=True)
return Response([Link])

URL generated: /books/recent/


Method: GET

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 55/66
Socratic Questions:

1. Why are custom actions useful in real-world APIs?


2. When would you choose a detail=True vs detail=False action?

Mini Exercise:

Add a mark_as_featured custom action to your BookViewSet.


Make it detail=True and update a featured field for that book.
Test via API: /books/<id>/mark_as_featured/.

Do you want me to move next to throttling and permission best practices for custom actions, which
is important in production APIs?

Api docs

Perfect! Let’s move to Module 11: API Documentation, which is crucial for making your DRF APIs
understandable, consumable, and professional.

Module 11: API Documentation in DRF


1. Why API Documentation?

Helps developers understand and use your API.


Saves time for frontend, mobile, or third-party developers.
Automatically generated docs reduce manual work.

2. DRF Built-in Browsable API

DRF provides a browsable web interface automatically at each endpoint.


Features:
Forms for POST, PUT, PATCH
Hyperlinked navigation between endpoints
Shows request/response examples
Example:

bash

[Link]

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 56/66
3. Swagger / OpenAPI Docs

For interactive, standardized docs, use drf-yasg or drf-spectacular.

Using drf-yasg

bash

pip install drf-yasg

[Link]:

python

from [Link] import path


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

schema_view = get_schema_view(
[Link](
title="Book API",
default_version='v1',
description="API documentation for Books",
),
public=True,
permission_classes=[[Link]],
)

urlpatterns = [
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

Visit /swagger/ for Swagger UI or /redoc/ for ReDoc UI.

4. Features of Swagger / ReDoc

Lists all endpoints with methods, parameters, request/response examples


Can try out API requests directly from the browser
Supports authentication and custom headers
Generates OpenAPI-compliant documentation, usable by tools like Postman or client code
generators

5. Best Practices for Documentation

Add descriptive help_text in your serializers and models


Use docstrings for ViewSets and custom actions
Include examples in serializers if possible
Ensure all endpoints are reachable and properly named

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 57/66
Socratic Questions:

1. Why is automatic API documentation important in team projects?


2. How can Swagger / ReDoc improve frontend-backend collaboration?

Mini Exercise:

Install drf-yasg and generate Swagger UI for your Book API.


Test submitting a request to create a book directly from the documentation.

Do you want me to next cover Authentication & Permissions in depth, which is critical for securing
your API in real-world apps?

Now provide notes for all you have teach

Absolutely! Here’s a comprehensive, structured set of notes covering everything we’ve gone through
in our Django REST Framework (DRF) learning path. I’ve organized it into modules for clarity and quick
reference.

Django REST Framework (DRF) Comprehensive Notes

Module 1: Introduction & Setup


DRF is a powerful toolkit for building Web APIs in Django.
Installation:

bash

pip install djangorestframework

Add to INSTALLED_APPS:

python

INSTALLED_APPS = [
'rest_framework',
]

Use ModelSerializer for quick serialization of Django models.


APIView vs ViewSet:
APIView → explicit, fine-grained control
ViewSet → automatic routing, less boilerplate, preferred in most industries

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 58/66
Module 2: CRUD Operations
Use ModelViewSet for full CRUD: list, retrieve, create, update, partial_update, destroy.
Custom create/update: Override perform_create or perform_update.
Nested Routes: Use kwargs like author_pk to filter nested resources:

python

def get_queryset(self):
author_id = [Link]['author_pk']
return [Link](author_id=author_id)

Module 3: Authentication & Permissions


Authentication: Who the user is (Token, JWT, Session)
Permissions: What the user can do (IsAuthenticated, IsAdminUser)
Custom permissions: Control actions like “user can only edit their own books”

Module 4: Throttling
Prevent abuse / control API usage.
Built-in throttles: UserRateThrottle, AnonRateThrottle
Custom throttles: Extend SimpleRateThrottle and define get_cache_key().
Example: limit free users, allow premium users unlimited access.

Module 5: Pagination
Break large querysets into manageable chunks.
Types:

Type URL Example Pros/Cons


PageNumberPagination ?page=2 Simple, may skip items if data changes
LimitOffsetPagination ?limit=10&offset=20 Flexible, may shift items if new records added
CursorPagination ?cursor=XYZ Efficient, stable, good for large datasets

Example: PAGE_SIZE=10, 105 books → 11 pages


Cursor avoids duplicate/skipped items during insertions.

Module 6: Filtering & Search


Filtering: Subset of data using query parameters

Manual: get_queryset() with request.query_params


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 59/66
Recommended: DjangoFilterBackend

python

filterset_fields = ['author', 'price']

Search: keyword search in specified fields

python

search_fields = ['title', 'description']

Ordering: sort results

python

ordering_fields = ['price', 'published_date']


ordering = ['published_date']

Combine all: ?author=3&search=django&ordering=-price

Module 7: Serializer Relationships


ForeignKey / One-to-Many: Book → Author
Basic: show author_id
Nested: show author details inside book
Writable: accept author_id in POST/PATCH
Many-to-Many: Book → Tags
Read-only nested: show all tag details

Writable: use PrimaryKeyRelatedField with many=True


Hyperlinked Relationships: Return URLs instead of full objects

python

author = HyperlinkedRelatedField(view_name='author-detail', read_only=True)

Module 8: ViewSet Actions & Custom Actions


Standard CRUD actions: list, retrieve, create, update, partial_update, destroy
Custom actions:

python

@action(detail=True, methods=['post'])
def publish(self, request, pk=None):

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 60/66
...

detail=True → operates on single object


detail=False → operates on list / collection

Module 9: API Documentation


Browsable API: built-in, interactive forms for endpoints
Swagger / ReDoc: interactive docs using drf-yasg or drf-spectacular
Best practices:
Use help_text in serializers/models
Docstrings for ViewSets / custom actions

Example responses

Industry Best Practices


Use ViewSets with routers for standard CRUD → less boilerplate
Use pagination for large datasets → improve performance
Use DjangoFilterBackend + Search + Ordering for flexible client queries
Use custom throttles and permissions for security and user-level restrictions
Use nested serializers or hyperlinked serializers carefully → balance readability and
performance
Maintain Swagger/ReDoc docs for team collaboration

These notes cover all the modules we’ve gone through: CRUD, authentication, throttling, pagination,
filtering, search, serializer relationships, custom actions, and documentation.

If you want, I can also create a concise one-page “DRF Cheat Sheet” with all commands, examples,
and endpoints for super quick reference.
Do you want me to do that?

make cheat sheet for whole converssation

Absolutely! Here’s a concise DRF Cheat Sheet covering everything we’ve discussed in this conversation.
It’s structured for quick reference and industry use.

Django REST Framework (DRF) Cheat Sheet


Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 61/66
1. Setup
bash

pip install djangorestframework django-filter drf-yasg

[Link]

python

INSTALLED_APPS += ['rest_framework', 'django_filters']


REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.[Link]',
'PAGE_SIZE': 10,
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

2. Models Example
python

class Author([Link]):
name = [Link](max_length=100)

class Tag([Link]):
name = [Link](max_length=50)

class Book([Link]):
title = [Link](max_length=100)
author = [Link](Author, on_delete=[Link])
tags = [Link](Tag, related_name='books')
price = [Link](max_digits=10, decimal_places=2)
published_date = [Link]()
featured = [Link](default=False)

3. Serializers
Basic ModelSerializer

python

class BookSerializer([Link]):
class Meta:
model = Book
fields = '__all__'

Nested Serializer

python

class AuthorSerializer([Link]):
class Meta: model = Author; fields = ['id','name']

class BookSerializer([Link]):

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 62/66
author = AuthorSerializer(read_only=True)
class Meta: model = Book; fields = ['id','title','author']

Many-to-Many Writable

python

class BookSerializer([Link]):
tags = [Link](many=True, queryset=[Link]())
class Meta: model = Book; fields = ['id','title','tags']

Hyperlinked Serializer

python

class BookSerializer([Link]):
class Meta:
model = Book
fields = ['url','id','title','author']

4. ViewSets & Routing


ModelViewSet

python

from rest_framework import viewsets

class BookViewSet([Link]):
queryset = [Link]()
serializer_class = BookSerializer

Custom Actions

python

from rest_framework.decorators import action


from rest_framework.response import Response

class BookViewSet([Link]):
...
@action(detail=True, methods=['post'])
def mark_as_featured(self, request, pk=None):
book = self.get_object()
[Link] = True
[Link]()
return Response({'status': 'book marked as featured'})

Nested Filtering Example

python

def get_queryset(self):
author_id = [Link]('author_pk')

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 63/66
return [Link](author_id=author_id)

5. Pagination
PageNumberPagination

python

from rest_framework.pagination import PageNumberPagination

class BookPagination(PageNumberPagination):
page_size = 10

LimitOffsetPagination

python

from rest_framework.pagination import LimitOffsetPagination

class BookLimitOffsetPagination(LimitOffsetPagination):
default_limit = 5
max_limit = 50

CursorPagination

python

from rest_framework.pagination import CursorPagination

class BookCursorPagination(CursorPagination):
page_size = 5
ordering = 'published_date'

6. Filtering, Search, Ordering


DjangoFilterBackend

python

filter_backends = [DjangoFilterBackend, [Link], [Link]]


filterset_fields = {'price':['gte','lte'],'author':['exact']}
search_fields = ['title','description']
ordering_fields = ['price','published_date']
ordering = ['published_date']

Examples:

sql

GET /books/?author=3&search=django&ordering=-price
GET /books/?price__gte=100&price__lte=500
GET /books/?published_date__year=2023

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 64/66
7. Authentication & Permissions
python

from rest_framework.permissions import IsAuthenticated

permission_classes = [IsAuthenticated]

Custom permission example: user can only update their own objects.
Common authentication: TokenAuthentication, SessionAuthentication, JWT.

8. Throttling
python

REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.[Link]',
'rest_framework.[Link]',
],
'DEFAULT_THROTTLE_RATES': {
'user': '100/day',
'anon': '10/day'
}
}

Custom throttle: extend SimpleRateThrottle and implement get_cache_key().

9. API Documentation
Browsable API

Built-in, accessible at endpoint /api/books/

Swagger / ReDoc

python

from drf_yasg.views import get_schema_view


from drf_yasg import openapi
from rest_framework import permissions

schema_view = get_schema_view(
[Link](title="Book API", default_version='v1'),
public=True,
permission_classes=[[Link]]
)

URLs:

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 65/66
bash

/swagger/ → Swagger UI
/redoc/ → ReDoc UI

10. Industry Best Practices


Prefer ModelViewSet + Routers → less boilerplate
Use pagination for large datasets
Combine filtering + search + ordering for flexible APIs
Use nested serializers carefully → balance readability vs performance
Use hyperlinked serializers for RESTful resource navigation

Secure APIs with authentication, permissions, and throttling


Maintain interactive API docs for team collaboration

✅ This cheat sheet gives you all key DRF concepts, code snippets, and best practices in one place.
If you want, I can also make a super compact one-page visual diagram showing all modules and
their connections for ultra-fast revision.
Do you want me to do that?

Printed using ChatGPT to PDF, powered by PDFCrowd HTML to PDF API. 66/66

Common questions

Powered by AI

A detail=False custom action is used when the endpoint operates on an entire collection rather than a single object. An example use case is a list action that returns a filtered subset of resources, such as retrieving the most recent books with GET /books/recent/ .

Hyperlinked serializers enhance RESTful resource navigation by embedding relationships via hyperlinks rather than primary keys. This approach aligns with REST principles by making APIs more self-descriptive and client-friendly, facilitating easier client-side access to related resources .

Throttle management limits request rates, protecting APIs from abuse such as brute force attacks. Common mechanisms in Django REST Framework include UserRateThrottle and AnonRateThrottle, with configurable limits like requests per day, ensuring fair use and minimizing server load .

Customization methods like perform_create allow developers to inject additional business logic during operations, such as automatically assigning the logged-in user as the author when creating a resource. This enhances flexibility while maintaining centralized domain logic consistent across the API .

Creating a custom action like /books/<id>/publish/ allows you to define a specific operation that is clear and isolated from standard CRUD operations, which keeps the API intuitive and operations logically separated. It prevents overloading the update endpoint, ensuring operations remain clear and consistent with RESTful principles .

Using DRF ViewSets in combination with Routers allows for a more scalable and less repetitive setup. ViewSets bundle all CRUD operations into a single class, which reduces the need to write separate views for each CRUD action. Routers then automatically generate the necessary URL routes, further simplifying the code and reducing manual configuration .

Cursor pagination is preferred in large-scale APIs with millions of records and rapidly changing datasets because it doesn't rely on OFFSET, which can become inefficient as dataset size grows. It provides stable pagination even when data changes between requests, eliminating the risk of duplicate or missed items .

DefaultRouter with ViewSets simplifies URL configuration by automatically generating routes, supporting RESTful design patterns without manually configuring each URL path. It is particularly advantageous in projects with multiple models needing uniform CRUD operations, minimizing redundancy and accelerating development .

DjangoFilterBackend centralizes and automates the filtering logic, allowing developers to define which fields can be filtered. This reduces the need for repetitive and error-prone manual filtering logic in methods like get_queryset(), improving code maintainability and scalability .

Routers automate the generation of standard CRUD URLs for multiple models, eliminating the need to manually define URLs for each model's operations. This streamlines development, reduces errors, and increases maintainability, especially beneficial in large projects with extensive data models .

You might also like