Django REST Framework: Mastering ReadOnlyModelViewSet
Last updated 1 month, 2 weeks ago | 131 views 75 5

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
, orDELETE
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