mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-11 04:07:39 +03:00
129 lines
4.3 KiB
Python
129 lines
4.3 KiB
Python
"""
|
|
Basic building blocks for generic class based views.
|
|
|
|
We don't bind behaviour to http method handlers yet,
|
|
which allows mixin classes to be composed in interesting ways.
|
|
"""
|
|
from __future__ import unicode_literals
|
|
|
|
from django.http import Http404
|
|
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
from rest_framework.request import clone_request
|
|
from rest_framework.settings import api_settings
|
|
|
|
|
|
class CreateModelMixin(object):
|
|
"""
|
|
Create a model instance.
|
|
"""
|
|
def create(self, request, *args, **kwargs):
|
|
serializer = self.get_serializer(data=request.DATA)
|
|
serializer.is_valid(raise_exception=True)
|
|
serializer.save()
|
|
headers = self.get_success_headers(serializer.data)
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
|
|
|
def get_success_headers(self, data):
|
|
try:
|
|
return {'Location': data[api_settings.URL_FIELD_NAME]}
|
|
except (TypeError, KeyError):
|
|
return {}
|
|
|
|
|
|
class ListModelMixin(object):
|
|
"""
|
|
List a queryset.
|
|
"""
|
|
def list(self, request, *args, **kwargs):
|
|
instance = self.filter_queryset(self.get_queryset())
|
|
page = self.paginate_queryset(instance)
|
|
if page is not None:
|
|
serializer = self.get_pagination_serializer(page)
|
|
else:
|
|
serializer = self.get_serializer(instance, many=True)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class RetrieveModelMixin(object):
|
|
"""
|
|
Retrieve a model instance.
|
|
"""
|
|
def retrieve(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
serializer = self.get_serializer(instance)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class UpdateModelMixin(object):
|
|
"""
|
|
Update a model instance.
|
|
"""
|
|
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)
|
|
serializer.save()
|
|
return Response(serializer.data)
|
|
|
|
def partial_update(self, request, *args, **kwargs):
|
|
kwargs['partial'] = True
|
|
return self.update(request, *args, **kwargs)
|
|
|
|
|
|
class DestroyModelMixin(object):
|
|
"""
|
|
Destroy a model instance.
|
|
"""
|
|
def destroy(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
instance.delete()
|
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
|
|
|
|
# The AllowPUTAsCreateMixin was previously the default behaviour
|
|
# for PUT requests. This has now been removed and must be *explictly*
|
|
# included if it is the behavior that you want.
|
|
# For more info see: ...
|
|
|
|
class AllowPUTAsCreateMixin(object):
|
|
"""
|
|
The following mixin class may be used in order to support PUT-as-create
|
|
behavior for incoming requests.
|
|
"""
|
|
def update(self, request, *args, **kwargs):
|
|
partial = kwargs.pop('partial', False)
|
|
instance = self.get_object_or_none()
|
|
serializer = self.get_serializer(instance, data=request.DATA, partial=partial)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
if instance is None:
|
|
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
|
lookup_value = self.kwargs[lookup_url_kwarg]
|
|
extras = {self.lookup_field: lookup_value}
|
|
serializer.save(extras=extras)
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
|
|
serializer.save()
|
|
return Response(serializer.data)
|
|
|
|
def partial_update(self, request, *args, **kwargs):
|
|
kwargs['partial'] = True
|
|
return self.update(request, *args, **kwargs)
|
|
|
|
def get_object_or_none(self):
|
|
try:
|
|
return self.get_object()
|
|
except Http404:
|
|
if self.request.method == 'PUT':
|
|
# For PUT-as-create operation, we need to ensure that we have
|
|
# relevant permissions, as if this was a POST request. This
|
|
# will either raise a PermissionDenied exception, or simply
|
|
# return None.
|
|
self.check_permissions(clone_request(self.request, 'POST'))
|
|
else:
|
|
# PATCH requests where the object does not exist should still
|
|
# return a 404 response.
|
|
raise
|