aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/mixins.py
diff options
context:
space:
mode:
authorTom Christie2012-10-30 14:32:31 +0000
committerTom Christie2012-10-30 14:32:31 +0000
commit9b30dab4f772f67a626e176dc4fae0a3ef9c2c81 (patch)
treeca138abf4792f58ffa28684f784f201ee1eef6d7 /rest_framework/mixins.py
parent7e5b1501b5cede61a9391fb1a751d2ebcdb37031 (diff)
parent4e7805cb24d73e7f706318b5e5a27e3f9ba39d14 (diff)
downloaddjango-rest-framework-9b30dab4f772f67a626e176dc4fae0a3ef9c2c81.tar.bz2
Merge branch 'restframework2' into rest-framework-2-merge2.0.0
Conflicts: .gitignore .travis.yml AUTHORS README.rst djangorestframework/mixins.py djangorestframework/renderers.py djangorestframework/resources.py djangorestframework/serializer.py djangorestframework/templates/djangorestframework/base.html djangorestframework/templates/djangorestframework/login.html djangorestframework/templatetags/add_query_param.py djangorestframework/tests/accept.py djangorestframework/tests/authentication.py djangorestframework/tests/content.py djangorestframework/tests/reverse.py djangorestframework/tests/serializer.py djangorestframework/views.py docs/examples.rst docs/examples/blogpost.rst docs/examples/modelviews.rst docs/examples/objectstore.rst docs/examples/permissions.rst docs/examples/pygments.rst docs/examples/views.rst docs/howto/alternativeframeworks.rst docs/howto/mixin.rst docs/howto/reverse.rst docs/howto/usingurllib2.rst docs/index.rst docs/topics/release-notes.md examples/sandbox/views.py rest_framework/__init__.py rest_framework/compat.py rest_framework/utils/breadcrumbs.py setup.py
Diffstat (limited to 'rest_framework/mixins.py')
-rw-r--r--rest_framework/mixins.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py
new file mode 100644
index 00000000..8873e4ae
--- /dev/null
+++ b/rest_framework/mixins.py
@@ -0,0 +1,116 @@
+"""
+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.
+
+Eg. Use mixins to build a Resource class, and have a Router class
+ perform the binding of http methods to actions for us.
+"""
+from django.http import Http404
+from rest_framework import status
+from rest_framework.response import Response
+
+
+class CreateModelMixin(object):
+ """
+ Create a model instance.
+ Should be mixed in with any `BaseView`.
+ """
+ def create(self, request, *args, **kwargs):
+ serializer = self.get_serializer(data=request.DATA)
+ if serializer.is_valid():
+ self.pre_save(serializer.object)
+ self.object = serializer.save()
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+ def pre_save(self, obj):
+ pass
+
+
+class ListModelMixin(object):
+ """
+ List a queryset.
+ Should be mixed in with `MultipleObjectBaseView`.
+ """
+ empty_error = u"Empty list and '%(class_name)s.allow_empty' is False."
+
+ def list(self, request, *args, **kwargs):
+ self.object_list = self.get_queryset()
+
+ # Default is to allow empty querysets. This can be altered by setting
+ # `.allow_empty = False`, to raise 404 errors on empty querysets.
+ allow_empty = self.get_allow_empty()
+ if not allow_empty and len(self.object_list) == 0:
+ error_args = {'class_name': self.__class__.__name__}
+ raise Http404(self.empty_error % error_args)
+
+ # Pagination size is set by the `.paginate_by` attribute,
+ # which may be `None` to disable pagination.
+ page_size = self.get_paginate_by(self.object_list)
+ if page_size:
+ packed = self.paginate_queryset(self.object_list, page_size)
+ paginator, page, queryset, is_paginated = packed
+ serializer = self.get_pagination_serializer(page)
+ else:
+ serializer = self.get_serializer(instance=self.object_list)
+
+ return Response(serializer.data)
+
+
+class RetrieveModelMixin(object):
+ """
+ Retrieve a model instance.
+ Should be mixed in with `SingleObjectBaseView`.
+ """
+ def retrieve(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ serializer = self.get_serializer(instance=self.object)
+ return Response(serializer.data)
+
+
+class UpdateModelMixin(object):
+ """
+ Update a model instance.
+ Should be mixed in with `SingleObjectBaseView`.
+ """
+ def update(self, request, *args, **kwargs):
+ try:
+ self.object = self.get_object()
+ except Http404:
+ self.object = None
+
+ serializer = self.get_serializer(data=request.DATA, instance=self.object)
+
+ if serializer.is_valid():
+ self.pre_save(serializer.object)
+ self.object = serializer.save()
+ return Response(serializer.data)
+
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+ def pre_save(self, obj):
+ """
+ Set any attributes on the object that are implicit in the request.
+ """
+ # pk and/or slug attributes are implicit in the URL.
+ pk = self.kwargs.get(self.pk_url_kwarg, None)
+ if pk:
+ setattr(obj, 'pk', pk)
+
+ slug = self.kwargs.get(self.slug_url_kwarg, None)
+ if slug:
+ slug_field = self.get_slug_field()
+ setattr(obj, slug_field, slug)
+
+
+class DestroyModelMixin(object):
+ """
+ Destroy a model instance.
+ Should be mixed in with `SingleObjectBaseView`.
+ """
+ def destroy(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ self.object.delete()
+ return Response(status=status.HTTP_204_NO_CONTENT)