Django REST Framework: Mastering ReadOnlyModelViewSet

Last updated 1 month, 2 weeks ago | 131 views 75     5

Tags:- Python Django DRF

In Django REST Framework, sometimes you want to expose data to be read, but not allow it to be modified. For such cases, ReadOnlyModelViewSet is the perfect tool.

This article covers:

  • What ReadOnlyModelViewSet is

  • When to use it

  • How to implement it

  • URL routing and endpoints

  • Tips, common use cases, and pitfalls


What is ReadOnlyModelViewSet?

ReadOnlyModelViewSet is a DRF class that provides read-only access to a queryset. It gives you:

  • GET /items/ → List all items

  • GET /items/<pk>/ → Retrieve a single item

It does not allow:

  • POST, PUT, PATCH, or DELETE methods.

This is ideal for exposing public or protected read-only data through an API.


When Should You Use It?

Use ReadOnlyModelViewSet when:

  • You want to make data available but not editable via the API.

  • You’re building a public-facing API or read-only dashboard.

  • Admins can edit data elsewhere, but users should only view it.


✅ Setup: Sample Article Model

# models.py
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    published_at = models.DateTimeField()

Create a Serializer

# serializers.py
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

Create the ReadOnlyModelViewSet

# views.py
from rest_framework.viewsets import ReadOnlyModelViewSet
from .models import Article
from .serializers import ArticleSerializer

class ArticleReadOnlyViewSet(ReadOnlyModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

Hook into URLs with a Router

# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleReadOnlyViewSet

router = DefaultRouter()
router.register(r'articles', ArticleReadOnlyViewSet)

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

Available Endpoints

Once set up, you automatically get:

HTTP Method URL Action
GET /articles/ List all articles
GET /articles/<pk>/ Retrieve a specific article
POST, PUT, DELETE Not allowed  

Trying any disallowed method will return:

{
  "detail": "Method \"POST\" not allowed."
}

Use Case Example: Public Blog Feed

A ReadOnlyModelViewSet is perfect for a public blog:

  • Visitors can view articles: GET /articles/

  • Editors use Django admin to manage content

  • No risk of accidental deletion or modification via API


Customizing Read Behavior

You can override methods for custom logic:

def get_queryset(self):
    return Article.objects.filter(published_at__isnull=False)

Or add filtering, pagination, etc.


Permissions Example

To restrict access to authenticated users only:

from rest_framework.permissions import IsAuthenticated

class ArticleReadOnlyViewSet(ReadOnlyModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = [IsAuthenticated]

⚠️ Common Pitfalls

Mistake Fix
Using ModelViewSet when only read is needed Use ReadOnlyModelViewSet instead
Forgetting to register with a router Use DefaultRouter().register()
Wanting to customize only list or retrieve Override .list() or .retrieve() methods
Trying to create or delete These methods are not available in ReadOnlyModelViewSet

Summary

Feature Description
ReadOnlyModelViewSet Provides list and retrieve actions only
Safe by default Blocks all write operations (POST, PUT, DELETE)
Use cases Public feeds, dashboards, analytics, documentation APIs
Easy to set up Just like ModelViewSet, but safer

What's Next?

Want to go deeper?

  • Add filtering and search to your read-only APIs

  • Learn how to build hybrid views (e.g., list-only or retrieve-only)

  • Add throttling or rate limiting for public APIs