diff options
| author | Tom Christie | 2013-04-09 18:45:15 +0100 | 
|---|---|---|
| committer | Tom Christie | 2013-04-09 18:45:15 +0100 | 
| commit | 099163f81f9d89746de50f3aed2955ead54dba4e (patch) | |
| tree | f72935d65c9e6f42d0d19f76cb23ba06d4c0ede7 /rest_framework | |
| parent | c73d0e1e39e661c7324eb0df8c3ce6e18f57915b (diff) | |
| download | django-rest-framework-099163f81f9d89746de50f3aed2955ead54dba4e.tar.bz2 | |
Removed SingleObjectMixin and MultipleObjectMixin
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/generics.py | 139 | ||||
| -rw-r--r-- | rest_framework/mixins.py | 5 | 
2 files changed, 106 insertions, 38 deletions
| diff --git a/rest_framework/generics.py b/rest_framework/generics.py index dea980a5..af3b69da 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -4,21 +4,35 @@ Generic views that provide commonly needed behaviour.  from __future__ import unicode_literals  from rest_framework import views, mixins  from rest_framework.settings import api_settings -from django.views.generic.detail import SingleObjectMixin -from django.views.generic.list import MultipleObjectMixin - +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.core.paginator import Paginator, InvalidPage +from django.http import Http404 +from django.utils.translation import ugettext as _  ### Base classes for the generic views ### +  class GenericAPIView(views.APIView):      """      Base class for all other generic views.      """ -    model = None +    queryset = None      serializer_class = None -    model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS +      filter_backend = api_settings.FILTER_BACKEND +    paginate_by = api_settings.PAGINATE_BY +    paginate_by_param = api_settings.PAGINATE_BY_PARAM +    pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS +    allow_empty = True +    page_kwarg = 'page' + +    # Pending deprecation +    model = None +    model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS +    pk_url_kwarg = 'pk'  # Not provided in Django 1.3 +    slug_url_kwarg = 'slug'  # Not provided in Django 1.3 +    slug_field = 'slug'      def filter_queryset(self, queryset):          """ @@ -82,15 +96,7 @@ class GenericAPIView(views.APIView):          """          pass - -class MultipleObjectAPIView(MultipleObjectMixin, GenericAPIView): -    """ -    Base class for generic views onto a queryset. -    """ - -    paginate_by = api_settings.PAGINATE_BY -    paginate_by_param = api_settings.PAGINATE_BY_PARAM -    pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS +    # Pagination      def get_pagination_serializer(self, page=None):          """ @@ -116,28 +122,81 @@ class MultipleObjectAPIView(MultipleObjectMixin, GenericAPIView):                  pass          return self.paginate_by - -class SingleObjectAPIView(SingleObjectMixin, GenericAPIView): -    """ -    Base class for generic views onto a model instance. -    """ - -    pk_url_kwarg = 'pk'  # Not provided in Django 1.3 -    slug_url_kwarg = 'slug'  # Not provided in Django 1.3 -    slug_field = 'slug' +    def paginate_queryset(self, queryset, page_size, paginator_class=Paginator): +        """ +        Paginate a queryset. +        """ +        paginator = paginator_class(queryset, page_size, allow_empty_first_page=self.allow_empty) +        page_kwarg = self.page_kwarg +        page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1 +        try: +            page_number = int(page) +        except ValueError: +            if page == 'last': +                page_number = paginator.num_pages +            else: +                raise Http404(_("Page is not 'last', nor can it be converted to an int.")) +        try: +            page = paginator.page(page_number) +            return (paginator, page, page.object_list, page.has_other_pages()) +        except InvalidPage as e: +            raise Http404(_('Invalid page (%(page_number)s): %(message)s') % { +                                'page_number': page_number, +                                'message': str(e) +            }) + +    def get_queryset(self): +        """ +        Get the list of items for this view. This must be an iterable, and may +        be a queryset (in which qs-specific behavior will be enabled). +        """ +        if self.queryset is not None: +            queryset = self.queryset +            if hasattr(queryset, '_clone'): +                queryset = queryset._clone() +        elif self.model is not None: +            queryset = self.model._default_manager.all() +        else: +            raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" +                                       % self.__class__.__name__) +        return queryset      def get_object(self, queryset=None):          """ -        Override default to add support for object-level permissions. +        Returns the object the view is displaying. +        By default this requires `self.queryset` and a `pk` or `slug` argument +        in the URLconf, but subclasses can override this to return any object.          """ -        obj = super(SingleObjectAPIView, self).get_object(queryset) +        # Use a custom queryset if provided; this is required for subclasses +        # like DateDetailView +        if queryset is None: +            queryset = self.get_queryset() +        # Next, try looking up by primary key. +        pk = self.kwargs.get(self.pk_url_kwarg, None) +        slug = self.kwargs.get(self.slug_url_kwarg, None) +        if pk is not None: +            queryset = queryset.filter(pk=pk) +        # Next, try looking up by slug. +        elif slug is not None: +            queryset = queryset.filter(**{self.slug_field: slug}) +        # If none of those are defined, it's an error. +        else: +            raise AttributeError("Generic detail view %s must be called with " +                                 "either an object pk or a slug." +                                 % self.__class__.__name__) +        try: +            # Get the single item from the filtered queryset +            obj = queryset.get() +        except ObjectDoesNotExist: +            raise Http404(_("No %(verbose_name)s found matching the query") % +                          {'verbose_name': queryset.model._meta.verbose_name}) +          self.check_object_permissions(self.request, obj)          return obj  ### Concrete view classes that provide method handlers ### -### by composing the mixin classes with a base view.   ### - +### by composing the mixin classes with the base view. ###  class CreateAPIView(mixins.CreateModelMixin,                      GenericAPIView): @@ -150,7 +209,7 @@ class CreateAPIView(mixins.CreateModelMixin,  class ListAPIView(mixins.ListModelMixin, -                  MultipleObjectAPIView): +                  GenericAPIView):      """      Concrete view for listing a queryset.      """ @@ -159,7 +218,7 @@ class ListAPIView(mixins.ListModelMixin,  class RetrieveAPIView(mixins.RetrieveModelMixin, -                      SingleObjectAPIView): +                      GenericAPIView):      """      Concrete view for retrieving a model instance.      """ @@ -168,7 +227,7 @@ class RetrieveAPIView(mixins.RetrieveModelMixin,  class DestroyAPIView(mixins.DestroyModelMixin, -                     SingleObjectAPIView): +                     GenericAPIView):      """      Concrete view for deleting a model instance. @@ -178,7 +237,7 @@ class DestroyAPIView(mixins.DestroyModelMixin,  class UpdateAPIView(mixins.UpdateModelMixin, -                    SingleObjectAPIView): +                    GenericAPIView):      """      Concrete view for updating a model instance. @@ -192,7 +251,7 @@ class UpdateAPIView(mixins.UpdateModelMixin,  class ListCreateAPIView(mixins.ListModelMixin,                          mixins.CreateModelMixin, -                        MultipleObjectAPIView): +                        GenericAPIView):      """      Concrete view for listing a queryset or creating a model instance.      """ @@ -205,7 +264,7 @@ class ListCreateAPIView(mixins.ListModelMixin,  class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,                              mixins.UpdateModelMixin, -                            SingleObjectAPIView): +                            GenericAPIView):      """      Concrete view for retrieving, updating a model instance.      """ @@ -221,7 +280,7 @@ class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,  class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,                               mixins.DestroyModelMixin, -                             SingleObjectAPIView): +                             GenericAPIView):      """      Concrete view for retrieving or deleting a model instance.      """ @@ -235,7 +294,7 @@ class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,  class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,                                     mixins.UpdateModelMixin,                                     mixins.DestroyModelMixin, -                                   SingleObjectAPIView): +                                   GenericAPIView):      """      Concrete view for retrieving, updating or deleting a model instance.      """ @@ -250,3 +309,13 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,      def delete(self, request, *args, **kwargs):          return self.destroy(request, *args, **kwargs) + + +### Deprecated classes ### + +class MultipleObjectAPIView(GenericAPIView): +    pass + + +class SingleObjectAPIView(GenericAPIView): +    pass diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index c700602e..b15cb11f 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -72,8 +72,7 @@ class ListModelMixin(object):          # 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 not self.object_list: +        if not self.allow_empty and not self.object_list:              class_name = self.__class__.__name__              error_msg = self.empty_error % {'class_name': class_name}              raise Http404(error_msg) @@ -148,7 +147,7 @@ class UpdateModelMixin(object):          # pk and/or slug attributes are implicit in the URL.          pk = self.kwargs.get(self.pk_url_kwarg, None)          slug = self.kwargs.get(self.slug_url_kwarg, None) -        slug_field = slug and self.get_slug_field() or None +        slug_field = slug and self.slug_field or None          if pk:              setattr(obj, 'pk', pk) | 
