Views
Types of Views in Django
1. Function-Based Views (FBVs):
- Simple functions that take a request and return a response.
- Use decorators like @api_view to specify allowed methods (GET, POST, etc.).
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET', 'POST'])
def my_view(request):
if request.method == 'GET':
= {"message": "Hello, world!"}
data return Response(data)
elif request.method == 'POST':
= request.data
data return Response(data)
2. Class-Based Views (CBVs):
- Inherit from Django’s View or DRF’s APIView.
- Provide more structure and functionality.
from rest_framework.views import APIView
from rest_framework.response import Response
class MyView(APIView):
def get(self, request):
= {"message": "Hello, world!"}
data return Response(data)
def post(self, request):
= request.data
data return Response(data)
Built-in Generic Views
Django provides a set of built-in generic views that handle common patterns. Examples include: - ListView
: Display a list of objects. - DetailView
: Display a single object. - CreateView
: Display a form for creating a new object. - UpdateView
: Display a form for updating an existing object. - DeleteView
: Display a confirmation page for deleting an object.
Generic Views
- Simplify common patterns (CRUD operations) by providing pre-built classes.
- Example: ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView
from rest_framework.generics import ListCreateAPIView
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelListCreateView(ListCreateAPIView):
= MyModel.objects.all()
queryset = MyModelSerializer serializer_class
ViewSets
- Combine logic for multiple views in a single class.
- Automatically create URLs for CRUD operations using a Router.
from rest_framework import viewsets
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelViewSet(viewsets.ModelViewSet):
= MyModel.objects.all()
queryset = MyModelSerializer serializer_class
Common Actions in Viewsets
Viewsets provide a variety of standard actions:
list: Retrieves a collection of objects.
/products/ GET
retrieve: Retrieves a single object based on its primary key.
/products/{id}/ GET
create: Creates a new object.
/products/ POST
update: Updates an existing object (entire object).
/products/{id}/ PUT
partial_update: Partially updates an object (only changes specific fields).
/products/{id}/ PATCH
destroy: Deletes an object.
/products/{id}/ DELETE
Routing for Viewsets
Instead of manually defining URLs, DRF provides routers that automatically map viewsets to URL patterns.
Step 1: Use DefaultRouter
to Automate URL Routing
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet
= DefaultRouter()
router r'products', ProductViewSet, basename='product')
router.register(
= router.urls urlpatterns
Resulting Routes:
GET /products/
→list
GET /products/{id}/
→retrieve
POST /products/
→create
PUT /products/{id}/
→update
PATCH /products/{id}/
→partial_update
DELETE /products/{id}/
→destroy
Customizing URL Paths: If you need to override or customize the URLs, you can use SimpleRouter
or register
with custom prefixes or basenames.
Custom Actions in Viewsets
Viewsets allow you to define custom actions that aren’t covered by the default CRUD operations using the @action
decorator.
Example of Custom Action:
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import viewsets
class ProductViewSet(viewsets.ModelViewSet):
= Product.objects.all()
queryset = ProductSerializer
serializer_class
# Custom action that returns products on sale
@action(detail=False, methods=['get'])
def on_sale(self, request):
= self.queryset.filter(on_sale=True)
products_on_sale = self.get_serializer(products_on_sale, many=True)
serializer return Response(serializer.data)
Key Features of @action
: - detail=False
: Means this is a collection-level action (works on the entire queryset, e.g., GET /products/on_sale/
). - detail=True
: For object-level actions (works on a single object, e.g., GET /products/{id}/related/
).
You can also specify the HTTP methods allowed for the action (e.g., methods=['post']
for a POST request).
Mixins in Viewsets
Mixins provide reusable behavior for viewsets, allowing you to include only the actions you need.
Common Mixins:
- ListModelMixin: Adds the
list()
action (returns a collection of objects). - CreateModelMixin: Adds the
create()
action. - RetrieveModelMixin: Adds the
retrieve()
action (retrieves a single object). - UpdateModelMixin: Adds the
update()
action (updates a single object). - DestroyModelMixin: Adds the
destroy()
action (deletes a single object).
Example Using Mixins:
from rest_framework import viewsets, mixins
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):= Product.objects.all()
queryset = ProductSerializer serializer_class
In this example: - Only list
and retrieve
actions are available. - You can mix and match to implement only the behaviors needed for your viewset.
You can combine mixins with GenericAPIView for custom behavior:
from rest_framework import mixins, generics
from .models import MyModel
from .serializers import MyModelSerializer
class MyModelView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
= MyModel.objects.all()
queryset = MyModelSerializer
serializer_class
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
URL Routing
DRF’s routers automatically generate URL patterns for ViewSets. Common routers include:
- SimpleRouter: Basic router for CRUD operations.
- DefaultRouter: Extends SimpleRouter with additional functionality like a default API root view.
from rest_framework.routers import DefaultRouter
from .views import MyModelViewSet
= DefaultRouter()
router r'mymodel', MyModelViewSet)
router.register(
= [
urlpatterns '', include(router.urls)),
path( ]
Customizing Views
Permissions
- Control access to views.
- Use permission_classes attribute or override get_permissions method.
from rest_framework.permissions import IsAuthenticated
class MyView(APIView):
= [IsAuthenticated]
permission_classes
def get(self, request):
= {"message": "Hello, authenticated user!"}
data return Response(data)
Throttling
- Limit the rate of requests.
- Use throttle_classes attribute or override get_throttles method.
from rest_framework.throttling import UserRateThrottle
class MyView(APIView):
= [UserRateThrottle]
throttle_classes
def get(self, request):
= {"message": "Hello, throttled user!"}
data return Response(data)
Filtering, Searching, and Ordering
- Use DjangoFilterBackend, SearchFilter, and OrderingFilter for filtering, searching, and ordering querysets.
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
class MyModelListCreateView(ListCreateAPIView):
= MyModel.objects.all()
queryset = MyModelSerializer
serializer_class = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filter_backends = ['field1', 'field2']
filterset_fields = ['field1', 'field2']
search_fields = ['field1', 'field2'] ordering_fields