2012-09-20 16:06:27 +04:00
|
|
|
"""
|
|
|
|
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.
|
|
|
|
"""
|
2012-11-22 03:20:49 +04:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2012-09-30 20:31:28 +04:00
|
|
|
from django.http import Http404
|
2012-09-20 16:06:27 +04:00
|
|
|
from rest_framework import status
|
|
|
|
from rest_framework.response import Response
|
2013-02-10 20:50:46 +04:00
|
|
|
from rest_framework.request import clone_request
|
2014-01-15 00:35:09 +04:00
|
|
|
from rest_framework.settings import api_settings
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
|
|
|
|
class CreateModelMixin(object):
|
|
|
|
"""
|
|
|
|
Create a model instance.
|
|
|
|
"""
|
|
|
|
def create(self, request, *args, **kwargs):
|
2014-09-26 13:46:52 +04:00
|
|
|
serializer = self.get_serializer(data=request.data)
|
2014-09-05 19:29:46 +04:00
|
|
|
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)
|
2012-11-17 01:27:34 +04:00
|
|
|
|
2012-11-14 16:24:20 +04:00
|
|
|
def get_success_headers(self, data):
|
2012-11-17 01:27:34 +04:00
|
|
|
try:
|
2014-01-15 00:35:09 +04:00
|
|
|
return {'Location': data[api_settings.URL_FIELD_NAME]}
|
2012-11-17 01:27:34 +04:00
|
|
|
except (TypeError, KeyError):
|
2012-11-13 22:15:42 +04:00
|
|
|
return {}
|
2012-11-17 01:27:34 +04:00
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
class ListModelMixin(object):
|
|
|
|
"""
|
|
|
|
List a queryset.
|
|
|
|
"""
|
|
|
|
def list(self, request, *args, **kwargs):
|
2014-09-05 19:29:46 +04:00
|
|
|
instance = self.filter_queryset(self.get_queryset())
|
|
|
|
page = self.paginate_queryset(instance)
|
2013-04-25 20:40:17 +04:00
|
|
|
if page is not None:
|
2012-09-30 20:31:28 +04:00
|
|
|
serializer = self.get_pagination_serializer(page)
|
|
|
|
else:
|
2014-09-05 19:29:46 +04:00
|
|
|
serializer = self.get_serializer(instance, many=True)
|
2012-09-20 16:06:27 +04:00
|
|
|
return Response(serializer.data)
|
|
|
|
|
|
|
|
|
|
|
|
class RetrieveModelMixin(object):
|
|
|
|
"""
|
|
|
|
Retrieve a model instance.
|
|
|
|
"""
|
|
|
|
def retrieve(self, request, *args, **kwargs):
|
2014-09-05 19:29:46 +04:00
|
|
|
instance = self.get_object()
|
|
|
|
serializer = self.get_serializer(instance)
|
2012-09-20 16:06:27 +04:00
|
|
|
return Response(serializer.data)
|
|
|
|
|
|
|
|
|
|
|
|
class UpdateModelMixin(object):
|
|
|
|
"""
|
|
|
|
Update a model instance.
|
|
|
|
"""
|
2013-05-18 01:09:23 +04:00
|
|
|
def update(self, request, *args, **kwargs):
|
|
|
|
partial = kwargs.pop('partial', False)
|
2014-09-05 19:29:46 +04:00
|
|
|
instance = self.get_object()
|
2014-09-26 13:46:52 +04:00
|
|
|
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
2014-09-05 19:29:46 +04:00
|
|
|
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)
|
|
|
|
|
2013-05-18 01:09:23 +04:00
|
|
|
|
2014-09-05 19:29:46 +04:00
|
|
|
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)
|
2012-10-08 15:52:56 +04:00
|
|
|
|
|
|
|
|
2014-09-05 19:29:46 +04:00
|
|
|
# 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()
|
2014-09-26 13:46:52 +04:00
|
|
|
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
2014-09-05 19:29:46 +04:00
|
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
|
|
|
|
if instance is None:
|
2014-09-02 20:41:23 +04:00
|
|
|
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
|
|
|
lookup_value = self.kwargs[lookup_url_kwarg]
|
|
|
|
extras = {self.lookup_field: lookup_value}
|
2014-09-05 19:29:46 +04:00
|
|
|
serializer.save(extras=extras)
|
2014-02-18 16:08:12 +04:00
|
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
2014-02-18 16:28:02 +04:00
|
|
|
|
2014-09-05 19:29:46 +04:00
|
|
|
serializer.save()
|
|
|
|
return Response(serializer.data)
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2013-04-05 01:24:30 +04:00
|
|
|
def partial_update(self, request, *args, **kwargs):
|
|
|
|
kwargs['partial'] = True
|
|
|
|
return self.update(request, *args, **kwargs)
|
|
|
|
|
2013-05-22 12:07:12 +04:00
|
|
|
def get_object_or_none(self):
|
|
|
|
try:
|
|
|
|
return self.get_object()
|
|
|
|
except Http404:
|
2013-08-13 15:26:30 +04:00
|
|
|
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:
|
2013-08-23 16:35:50 +04:00
|
|
|
# PATCH requests where the object does not exist should still
|
|
|
|
# return a 404 response.
|
2013-08-13 15:26:30 +04:00
|
|
|
raise
|