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 objectsserializer_class: The serializer class to use
List view specific:
pagination_class: Controls pagination behaviorfilter_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 pkdetail=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