Django REST Framework Views: Requests, Responses, and View Classes

Request and Response Objects

Request

The request object passed to views in REST framework is not Django's standard HttpRequest. Instead, REST framework provides an extended Request class that inherits from HttpRequest.

REST framework includes Parser components that automatically parse incoming request data based on the Content-Type header. Whether the data arrives as JSON, form data, or another format, the parser converts it into a dictionary-like object stored within the Request object.

Key Attributes

data
The request.data property returns the parsed request body content. Unlike Django's request.POST and request.FILES, this attribute:

  • Contains both file and non-file data
  • Handles POST, PUT, and PATCH requests uniformly
  • Supports multiple data formats through REST framework's parsers, including JSON and form data

query_params
The request.query_params property is equivalent to Django's request.GET but uses a more semantically appropriate name.

Response

REST framework provides a Response class that handles automatic rendering of response data into formats required by the client. When constructing a Response object, the data undergoes rendering to match the client's expected format.

The Renderer system determines the appropriate output format by examining the Accept header in the request. If the client does not specify an Accept header, the default renderer is used. You can configure this default behavior in settings.py:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    )
}

Response Constructor

Response(data, status=None, template_name=None, headers=None, content_type=None)

The data parameter should contain Python native types, not pre-rendered data. REST framework handles the rendering automatically.

Important: The data parameter must be a Python dictionary or list. Complex objects like Django model instances must be serialized first using a serializer to convert them into primitive types before passing to the Response constructor.

Parameters

Parameter Description
data Serialized data prepared for response
status HTTP status code, defaults to 200
template_name Template name when using HTMLRenderer
headers Dictionary for response headers
content_type Content-Type header, usually auto-detected

Response Properties

  • data: Serialized data before rendering
  • status_code: Numeric HTTP status code
  • content: Rendered response data ready for transmission

Status Codes

REST framework provides status code constants in rest_framework.status for improved code readability:

# Informational - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS

# Success - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS

# Redirection - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT

# Client Error - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS

# Server Error - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

Base View Clases

APIView

The rest_framework.views.APIView class serves as the foundation for all REST framework views, inheriting from Django's View class.

Differences from Django's View

  • Requests use REST framework's Request object instead of HttpRequest
  • Responses use REST framework's Response object with automatic rendering
  • APIException errors are caught and converted to appropriate error responses
  • Authentication, permissions, and throttling checks occur before dispatch()

Configurable Properties

authentication_classes  # List or tuple of authentication classes
permission_classes      # List or tuple of permission classes
throttle_classes        # List or tuple of throttle classes

Example

from rest_framework.views import APIView
from rest_framework.response import Response

class PublicationListView(APIView):
    def get(self, request):
        publications = Publication.objects.filter(is_active=True)
        serializer = PublicationSerializer(publications, many=True)
        return Response(serializer.data)

GenericAPIView

The rest_framework.generics.GenericAPIView extends APIView with additional support methods for list and detail views. It is typically combined with one or more Mixin classes.

Configurable Properties

Common to list and detail views:

  • queryset: The base queryset for retrieving objects
  • serializer_class: The serializer class to use

List view specific:

  • pagination_class: Controls pagination behavior
  • filter_backends: Configures filtering backends

Detail view specific:

  • lookup_field: The field used for object lookup (default: 'pk')
  • lookup_url_kwarg: URL parameter name for lookup (default: same as lookup_field)

Provided Methods

get_queryset():
Returns the queryset for the view. Override this method to dynamically filter results based on the request:

def get_queryset(self):
    current_user = self.request.user
    return current_user.owned_items.filter(status='active')

get_serializer_class():
Returns the appropriate serializer class. Use this to select different serializers based on context:

def get_serializer_class(self):
    if self.request.user.is_superuser:
        return FullDetailsSerializer
    return LimitedDetailsSerializer

get_serializer(*args, **kwargs):
Returns a serializer instance. REST framework automatically populates the context dictionary with request, format, and view keys.

get_object():
Returns the model instance for detail views. Uses lookup_field to filter the queryset. Returns 404 if the object does not exist and applies permission checks:

class PublicationDetailView(GenericAPIView):
    queryset = Publication.objects.all()
    serializer_class = PublicationSerializer
    
    def get(self, request, identifier):
        publication = self.get_object()
        serializer = self.get_serializer(publication)
        return Response(serializer.data)

Mixin Classes

ListModelMixin

Provides the list() method for implementing list views. Automatically applies filtering and pagination before returning results with a 200 status code:

class ListModelMixin:
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Usage:

class ArticleListView(ListModelMixin, GenericAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    def get(self, request):
        return self.list(request)

CreateModelMixin

Provides the create() method for resource creation. Returns 201 on success, or 400 if validation fails:

class CreateModelMixin:
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
    def perform_create(self, serializer):
        serializer.save()
    
    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

RetrieveModelMixin

Provides the retrieve() method for detail views. Returns 200 if the object exists, 404 otherwise:

class RetrieveModelMixin:
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

Usage:

class ArticleDetailView(RetrieveModelMixin, GenericAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    def get(self, request, pk):
        return self.retrieve(request)

UpdateModelMixin

Provides update() and partial_update() methods for modifying existing resources. Returns 200 on success, 400 on validation failure:

class UpdateModelMixin:
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        
        if getattr(instance, '_prefetched_objects_cache', None):
            instance._prefetched_objects_cache = {}
        
        return Response(serializer.data)
    
    def perform_update(self, serializer):
        serializer.save()
    
    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

DestroyModelMixin

Provides the destroy() method for deleting resources. Returns 204 on success, 404 if the object does not exist:

class DestroyModelMixin:
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)
    
    def perform_destroy(self, instance):
        instance.delete()

Concrete Generic Views

REST framework provides pre-built view classes combining common patterns:

View Class Methods Parent Classes
CreateAPIView POST GenericAPIView, CreateModelMixin
ListAPIView GET GenericAPIView, ListModelMixin
RetrieveAPIView GET GenericAPIView, RetrieveModelMixin
DestroyAPIView DELETE GenericAPIView, DestroyModelMixin
UpdateAPIView PUT, PATCH GenericAPIView, UpdateModelMixin
RetrieveUpdateAPIView GET, PUT, PATCH GenericAPIView, RetrieveModelMixin, UpdateModelMixin
RetrieveUpdateDestroyAPIView GET, PUT, PATCH, DELETE GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

ViewSets

ViewSets consolidate related actions into a single class. Unlike traditional views that define HTTP methods like get() and post(), ViewSets define actions like list(), create(), retrieve(), update(), and destroy().

The mapping between HTTP methods and actions occurs when as_view() is called, typically in URL configuration:

class DocumentViewSet(viewsets.ViewSet):
    def list(self, request):
        documents = Document.objects.filter(is_published=True)
        serializer = DocumentSerializer(documents, many=True)
        return Response(serializer.data)
    
    def retrieve(self, request, pk=None):
        document = self.get_object()
        serializer = DocumentSerializer(document)
        return Response(serializer.data)

URL configuration:

urlpatterns = [
    url(r'^documents/$', DocumentViewSet.as_view({'get': 'list'})),
    url(r'^documents/(?P<pk>\d+)/$', DocumentViewSet.as_view({'get': 'retrieve'}))
]

Action Property

The action property on the view instance indicates which action is currently being executed:

def get_serializer_class(self):
    if self.action == 'create':
        return OrderSubmitSerializer
    elif self.action == 'list':
        return OrderSummarySerializer
    return OrderDetailSerializer

Custom Actions with @action Decorator

Add extra actions using the action decorator. The decorated method name becomes the action identifier:

from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action

class PublicationViewSet(mixins.ListModelMixin, 
                         mixins.RetrieveModelMixin, 
                         GenericViewSet):
    queryset = Publication.objects.all()
    serializer_class = PublicationSerializer
    
    @action(methods=['get'], detail=False)
    def newest(self, request):
        """Returns the most recently created publication."""
        publication = Publication.objects.order_by('-created_at').first()
        serializer = self.get_serializer(publication)
        return Response(serializer.data)
    
    @action(methods=['post'], detail=True)
    def archive(self, request, pk=None):
        """Archives a specific publication."""
        publication = self.get_object()
        publication.is_archived = True
        publication.save()
        serializer = self.get_serializer(publication)
        return Response(serializer.data)

The detail parameter:

  • detail=True: Action operates on a specific object identified by URL pk
  • detail=False: Action operates on the collection without requiring a pk

Routers

Routers automate URL configuration for ViewSets. REST framework provides two router classes:

SimpleRouter

Basic router generating standard CRUD routes:

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'publications', PublicationViewSet, base_name='pub')

Generated routes:

^publications/$     name: pub-list
^publications/{pk}/$ name: pub-detail

DefaultRouter

Extends SimpleRouter with an API root endpoint that returns hyperlinks to all available views:

from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'publications', PublicationViewSet, base_name='pub')

Generated routes include:

^$                     name: api-root
^publications/$        name: pub-list
^publications/{pk}/$   name: pub-detail

Router Registration

Include router URLs in your URL patterns:

urlpatterns = [
    # your other patterns
]
urlpatterns += router.urls

Or nest them:

urlpatterns = [
    url(r'^api/', include(router.urls))
]

Routing for Custom Actions

Custom actions registered with @action automatically receive routes:

class PublicationViewSet(mixins.ListModelMixin, 
                         mixins.RetrieveModelMixin, 
                         GenericViewSet):
    queryset = Publication.objects.all()
    serializer_class = PublicationSerializer
    
    @action(methods=['get'], detail=False)
    def newest(self, request):
        pass
    
    @action(methods=['patch'], detail=True)
    def archive(self, request, pk=None):
        pass

Generated routes for custom actions:

^publications/newest/$   name: pub-newest
^publications/{pk}/archive/$ name: pub-archive

Tags: Django Django REST Framework API views Requests

Posted on Thu, 07 May 2026 06:21:36 +0000 by djdog.us