Mini-Build: Full REST API with CRUD
Build a complete REST API for a blog: CRUD endpoints, JWT authentication, permissions, filtering, search, ordering, and pagination. This mini-build combines all Module 8 concepts into a production-ready API.
25 min•By Priygop Team•Updated 2026
API Features
- Full CRUD for posts, comments, categories
- JWT authentication (login, refresh tokens)
- IsAuthorOrReadOnly permission
- Filter by category, search by title/content
- Ordering by date, views
- Pagination (10 per page)
- Nested comments in post detail
- Custom action: publish/unpublish posts
Complete API
Complete API
# Complete Blog REST API
# blog/serializers.py
# class CategorySerializer(serializers.ModelSerializer):
# post_count = serializers.IntegerField(source='posts.count', read_only=True)
# class Meta:
# model = Category
# fields = ['id', 'name', 'slug', 'post_count']
# class PostListSerializer(serializers.ModelSerializer):
# author_name = serializers.CharField(source='author.username', read_only=True)
# class Meta:
# model = Post
# fields = ['id', 'title', 'slug', 'author_name', 'category',
# 'published', 'created_at', 'views_count']
# blog/views.py
# class PostViewSet(viewsets.ModelViewSet):
# serializer_class = PostListSerializer
# permission_classes = [IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly]
# filterset_fields = ['category', 'published']
# search_fields = ['title', 'content']
# ordering_fields = ['created_at', 'views_count']
# ordering = ['-created_at']
#
# def get_queryset(self):
# return Post.objects.select_related('author', 'category')
#
# def perform_create(self, serializer):
# serializer.save(author=self.request.user)
#
# @action(detail=True, methods=['post'])
# def publish(self, request, pk=None):
# post = self.get_object()
# post.published = True
# post.save()
# return Response({'status': 'published'})
# blog/urls.py
# router = DefaultRouter()
# router.register('posts', PostViewSet, basename='post')
# router.register('categories', CategoryViewSet)
# urlpatterns = [
# path('api/', include(router.urls)),
# path('api/token/', TokenObtainPairView.as_view()),
# path('api/token/refresh/', TokenRefreshView.as_view()),
# ]Tip
Tip
Use select_related/prefetch_related in get_queryset() to optimize API response times with fewer database queries.
Diagram
Loading diagram…
QuerySets are LAZY — no DB hit until evaluated.
Common Mistake
Warning
Not optimizing database queries in API views. N+1 queries make APIs slow. Always use select_related/prefetch_related.
Practice Task
Note
(1) Use django-debug-toolbar to count API queries. (2) Add select_related. (3) Compare response times.
Quick Quiz
Key Takeaways
- Build a complete REST API for a blog: CRUD endpoints, JWT authentication, permissions, filtering, search, ordering, and pagination.
- Full CRUD for posts, comments, categories
- JWT authentication (login, refresh tokens)
- IsAuthorOrReadOnly permission