From faf76a4b75f12f3fa9de4e3ec455daa239af4d89 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 31 Dec 2014 12:49:20 +0000 Subject: fix spelling & grammar errors --- rest_framework/generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index e6db155e..bdbc19a7 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -119,7 +119,7 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise Http404(_("Page is not 'last', nor can it be converted to an int.")) + raise Http404(_("Page is not 'last', and cannot be converted to an int.")) try: page = paginator.page(page_number) except InvalidPage as exc: -- cgit v1.2.3 From a90ba2bc11de5fb391b95d4fce84f87ae7f88eff Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 31 Dec 2014 13:03:16 +0000 Subject: update error messages for language and consistency --- rest_framework/generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index bdbc19a7..680992d7 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -119,7 +119,7 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise Http404(_("Page is not 'last', and cannot be converted to an int.")) + raise Http404(_("Choose a valid page number. Page numbers must be a whole number, or must be the string 'last'.")) try: page = paginator.page(page_number) except InvalidPage as exc: -- cgit v1.2.3 From 9b4177b6ea38de6e86b0fe723834b6ef36af15b3 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 11:41:06 +0000 Subject: switch to using format strings in error messages; raise NotFound when pagination fails to provide a more useful error message --- rest_framework/generics.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 680992d7..fe92355d 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -10,6 +10,7 @@ from django.shortcuts import get_object_or_404 as _get_object_or_404 from django.utils import six from django.utils.translation import ugettext as _ from rest_framework import views, mixins +from rest_framework.exceptions import NotFound from rest_framework.settings import api_settings @@ -119,15 +120,16 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise Http404(_("Choose a valid page number. Page numbers must be a whole number, or must be the string 'last'.")) + raise NotFound(_("Choose a valid page number. Page numbers must be a whole number, or must be the string 'last'.")) + + page_number = -1 try: page = paginator.page(page_number) except InvalidPage as exc: - error_format = _('Invalid page (%(page_number)s): %(message)s') - raise Http404(error_format % { - 'page_number': page_number, - 'message': six.text_type(exc) - }) + error_format = _('Invalid page ({page_number}): {message}') + raise NotFound(error_format.format( + page_number=page_number, message=six.text_type(exc) + )) return page -- cgit v1.2.3 From fe5d93c8cbc5f3a9b1b6715208c70f485be68bdf Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 11:44:18 +0000 Subject: remove hardcoded page number --- rest_framework/generics.py | 1 - 1 file changed, 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index fe92355d..7c4d5e95 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -122,7 +122,6 @@ class GenericAPIView(views.APIView): else: raise NotFound(_("Choose a valid page number. Page numbers must be a whole number, or must be the string 'last'.")) - page_number = -1 try: page = paginator.page(page_number) except InvalidPage as exc: -- cgit v1.2.3 From 4c32083b8b59a50877633910055313dad7bb117e Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:01:11 +0000 Subject: use double quotes for user visible strings; end user visible strings in full stops; add some missing translation tags --- rest_framework/generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 7c4d5e95..c7053d8f 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -125,7 +125,7 @@ class GenericAPIView(views.APIView): try: page = paginator.page(page_number) except InvalidPage as exc: - error_format = _('Invalid page ({page_number}): {message}') + error_format = _("Invalid page ({page_number}): {message}.") raise NotFound(error_format.format( page_number=page_number, message=six.text_type(exc) )) -- cgit v1.2.3 From 9a4267049ba37883e3e0c21b5d453b9551343b8d Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:33:37 +0000 Subject: use double quotes in user messages --- rest_framework/generics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index c7053d8f..738ba544 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -120,12 +120,12 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise NotFound(_("Choose a valid page number. Page numbers must be a whole number, or must be the string 'last'.")) + raise NotFound(_("Choose a valid page number. Page numbers must be a whole number, or must be the string \"last\".")) try: page = paginator.page(page_number) except InvalidPage as exc: - error_format = _("Invalid page ({page_number}): {message}.") + error_format = _("Invalid page \"{page_number}\": {message}.") raise NotFound(error_format.format( page_number=page_number, message=six.text_type(exc) )) -- cgit v1.2.3 From 91e316f7810157474d6246cd0024bd7f7cc31ff7 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 12:46:23 +0000 Subject: prefer single quotes in source and double quotes in user visible strings; add some missing full stops to user visible strings --- rest_framework/generics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 738ba544..7ebed032 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -120,12 +120,12 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise NotFound(_("Choose a valid page number. Page numbers must be a whole number, or must be the string \"last\".")) + raise NotFound(_('Choose a valid page number. Page numbers must be a whole number, or must be the string "last".')) try: page = paginator.page(page_number) except InvalidPage as exc: - error_format = _("Invalid page \"{page_number}\": {message}.") + error_format = _('Invalid page "{page_number}": {message}.') raise NotFound(error_format.format( page_number=page_number, message=six.text_type(exc) )) -- cgit v1.2.3 From 734f8f26678d3bd28f04bc44b0fabd146b97ddb0 Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Wed, 7 Jan 2015 18:22:40 +0000 Subject: restore Django 404 --- rest_framework/generics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 7ebed032..d52f2b6c 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -120,13 +120,13 @@ class GenericAPIView(views.APIView): if page == 'last': page_number = paginator.num_pages else: - raise NotFound(_('Choose a valid page number. Page numbers must be a whole number, or must be the string "last".')) + raise Http404(_('Choose a valid page number. Page numbers must be a whole number, or must be the string "last".')) try: page = paginator.page(page_number) except InvalidPage as exc: error_format = _('Invalid page "{page_number}": {message}.') - raise NotFound(error_format.format( + raise Http404(error_format.format( page_number=page_number, message=six.text_type(exc) )) -- cgit v1.2.3 From 1368c31a705a4892995f42cf5e0dcdcbfa13a1ce Mon Sep 17 00:00:00 2001 From: Craig Blaszczyk Date: Thu, 8 Jan 2015 17:16:15 +0000 Subject: remove unused import --- rest_framework/generics.py | 1 - 1 file changed, 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index d52f2b6c..0d709c37 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -10,7 +10,6 @@ from django.shortcuts import get_object_or_404 as _get_object_or_404 from django.utils import six from django.utils.translation import ugettext as _ from rest_framework import views, mixins -from rest_framework.exceptions import NotFound from rest_framework.settings import api_settings -- cgit v1.2.3 From 73feaf6299827607eab94ce96b77b73671880626 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 9 Jan 2015 15:30:36 +0000 Subject: First pass at 3.1 pagination API --- rest_framework/generics.py | 220 +++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 150 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 0d709c37..12fb6413 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -2,29 +2,13 @@ Generic views that provide commonly needed behaviour. """ from __future__ import unicode_literals - -from django.core.paginator import Paginator, InvalidPage from django.db.models.query import QuerySet from django.http import Http404 from django.shortcuts import get_object_or_404 as _get_object_or_404 -from django.utils import six -from django.utils.translation import ugettext as _ from rest_framework import views, mixins from rest_framework.settings import api_settings -def strict_positive_int(integer_string, cutoff=None): - """ - Cast a string to a strictly positive integer. - """ - ret = int(integer_string) - if ret <= 0: - raise ValueError() - if cutoff: - ret = min(ret, cutoff) - return ret - - def get_object_or_404(queryset, *filter_args, **filter_kwargs): """ Same as Django's standard shortcut, but make sure to also raise 404 @@ -40,7 +24,6 @@ class GenericAPIView(views.APIView): """ Base class for all other generic views. """ - # You'll need to either set these attributes, # or override `get_queryset()`/`get_serializer_class()`. # If you are overriding a view method, it is important that you call @@ -50,146 +33,16 @@ class GenericAPIView(views.APIView): queryset = None serializer_class = None - # If you want to use object lookups other than pk, set this attribute. + # If you want to use object lookups other than pk, set 'lookup_field'. # For more complex lookup requirements override `get_object()`. lookup_field = 'pk' lookup_url_kwarg = None - # Pagination settings - paginate_by = api_settings.PAGINATE_BY - paginate_by_param = api_settings.PAGINATE_BY_PARAM - max_paginate_by = api_settings.MAX_PAGINATE_BY - pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS - page_kwarg = 'page' - # The filter backend classes to use for queryset filtering filter_backends = api_settings.DEFAULT_FILTER_BACKENDS - # The following attribute may be subject to change, - # and should be considered private API. - paginator_class = Paginator - - def get_serializer_context(self): - """ - Extra context provided to the serializer class. - """ - return { - 'request': self.request, - 'format': self.format_kwarg, - 'view': self - } - - def get_serializer(self, *args, **kwargs): - """ - Return the serializer instance that should be used for validating and - deserializing input, and for serializing output. - """ - serializer_class = self.get_serializer_class() - kwargs['context'] = self.get_serializer_context() - return serializer_class(*args, **kwargs) - - def get_pagination_serializer(self, page): - """ - Return a serializer instance to use with paginated data. - """ - class SerializerClass(self.pagination_serializer_class): - class Meta: - object_serializer_class = self.get_serializer_class() - - pagination_serializer_class = SerializerClass - context = self.get_serializer_context() - return pagination_serializer_class(instance=page, context=context) - - def paginate_queryset(self, queryset): - """ - Paginate a queryset if required, either returning a page object, - or `None` if pagination is not configured for this view. - """ - page_size = self.get_paginate_by() - if not page_size: - return None - - paginator = self.paginator_class(queryset, page_size) - page_kwarg = self.kwargs.get(self.page_kwarg) - page_query_param = self.request.query_params.get(self.page_kwarg) - page = page_kwarg or page_query_param or 1 - try: - page_number = paginator.validate_number(page) - except InvalidPage: - if page == 'last': - page_number = paginator.num_pages - else: - raise Http404(_('Choose a valid page number. Page numbers must be a whole number, or must be the string "last".')) - - try: - page = paginator.page(page_number) - except InvalidPage as exc: - error_format = _('Invalid page "{page_number}": {message}.') - raise Http404(error_format.format( - page_number=page_number, message=six.text_type(exc) - )) - - return page - - def filter_queryset(self, queryset): - """ - Given a queryset, filter it with whichever filter backend is in use. - - You are unlikely to want to override this method, although you may need - to call it either from a list view, or from a custom `get_object` - method if you want to apply the configured filtering backend to the - default queryset. - """ - for backend in self.get_filter_backends(): - queryset = backend().filter_queryset(self.request, queryset, self) - return queryset - - def get_filter_backends(self): - """ - Returns the list of filter backends that this view requires. - """ - return list(self.filter_backends) - - # The following methods provide default implementations - # that you may want to override for more complex cases. - - def get_paginate_by(self): - """ - Return the size of pages to use with pagination. - - If `PAGINATE_BY_PARAM` is set it will attempt to get the page size - from a named query parameter in the url, eg. ?page_size=100 - - Otherwise defaults to using `self.paginate_by`. - """ - if self.paginate_by_param: - try: - return strict_positive_int( - self.request.query_params[self.paginate_by_param], - cutoff=self.max_paginate_by - ) - except (KeyError, ValueError): - pass - - return self.paginate_by - - def get_serializer_class(self): - """ - Return the class to use for the serializer. - Defaults to using `self.serializer_class`. - - You may want to override this if you need to provide different - serializations depending on the incoming request. - - (Eg. admins get full serialization, others get basic serialization) - """ - assert self.serializer_class is not None, ( - "'%s' should either include a `serializer_class` attribute, " - "or override the `get_serializer_class()` method." - % self.__class__.__name__ - ) - - return self.serializer_class + # The style to use for queryset pagination. + pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): """ @@ -246,6 +99,73 @@ class GenericAPIView(views.APIView): return obj + def get_serializer(self, *args, **kwargs): + """ + Return the serializer instance that should be used for validating and + deserializing input, and for serializing output. + """ + serializer_class = self.get_serializer_class() + kwargs['context'] = self.get_serializer_context() + return serializer_class(*args, **kwargs) + + def get_serializer_class(self): + """ + Return the class to use for the serializer. + Defaults to using `self.serializer_class`. + + You may want to override this if you need to provide different + serializations depending on the incoming request. + + (Eg. admins get full serialization, others get basic serialization) + """ + assert self.serializer_class is not None, ( + "'%s' should either include a `serializer_class` attribute, " + "or override the `get_serializer_class()` method." + % self.__class__.__name__ + ) + + return self.serializer_class + + def get_serializer_context(self): + """ + Extra context provided to the serializer class. + """ + return { + 'request': self.request, + 'format': self.format_kwarg, + 'view': self + } + + def filter_queryset(self, queryset): + """ + Given a queryset, filter it with whichever filter backend is in use. + + You are unlikely to want to override this method, although you may need + to call it either from a list view, or from a custom `get_object` + method if you want to apply the configured filtering backend to the + default queryset. + """ + for backend in list(self.filter_backends): + queryset = backend().filter_queryset(self.request, queryset, self) + return queryset + + @property + def pager(self): + if not hasattr(self, '_pager'): + if self.pagination_class is None: + self._pager = None + else: + self._pager = self.pagination_class() + return self._pager + + def paginate_queryset(self, queryset): + if self.pager is None: + return None + return self.pager.paginate_queryset(queryset, self.request, view=self) + + def get_paginated_response(self, objects): + return self.pager.get_paginated_response(objects) + # Concrete view classes that provide method handlers # by composing the mixin classes with the base view. -- cgit v1.2.3 From 1bcec3a0ac4346b31b655a08505d3e3dc2156604 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 13 Jan 2015 17:14:13 +0000 Subject: API tweaks and pagination documentation --- rest_framework/generics.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 12fb6413..cdf6ece0 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -160,11 +160,11 @@ class GenericAPIView(views.APIView): def paginate_queryset(self, queryset): if self.pager is None: - return None + return queryset return self.pager.paginate_queryset(queryset, self.request, view=self) - def get_paginated_response(self, objects): - return self.pager.get_paginated_response(objects) + def get_paginated_response(self, data): + return self.pager.get_paginated_response(data) # Concrete view classes that provide method handlers -- cgit v1.2.3 From d76e83dd78627a0cf4bcd4b28a7710fb678d8d4e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 15 Jan 2015 16:52:07 +0000 Subject: Tweaks, and add pagination controls for offset/limit. --- rest_framework/generics.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index cdf6ece0..4cc4c64d 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -150,21 +150,21 @@ class GenericAPIView(views.APIView): return queryset @property - def pager(self): - if not hasattr(self, '_pager'): + def paginator(self): + if not hasattr(self, '_paginator'): if self.pagination_class is None: - self._pager = None + self._paginator = None else: - self._pager = self.pagination_class() - return self._pager + self._paginator = self.pagination_class() + return self._paginator def paginate_queryset(self, queryset): - if self.pager is None: + if self.paginator is None: return queryset - return self.pager.paginate_queryset(queryset, self.request, view=self) + return self.paginator.paginate_queryset(queryset, self.request, view=self) def get_paginated_response(self, data): - return self.pager.get_paginated_response(data) + return self.paginator.get_paginated_response(data) # Concrete view classes that provide method handlers -- cgit v1.2.3 From 8b0f25aa0a91cb7b56f9ce4dde4330fe5daaad9b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 16 Jan 2015 16:55:46 +0000 Subject: More pagination tests & cleanup --- rest_framework/generics.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'rest_framework/generics.py') diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 4cc4c64d..61dcb84a 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -151,6 +151,9 @@ class GenericAPIView(views.APIView): @property def paginator(self): + """ + The paginator instance associated with the view, or `None`. + """ if not hasattr(self, '_paginator'): if self.pagination_class is None: self._paginator = None @@ -159,11 +162,18 @@ class GenericAPIView(views.APIView): return self._paginator def paginate_queryset(self, queryset): + """ + Return a single page of results, or `None` if pagination is disabled. + """ if self.paginator is None: - return queryset + return None return self.paginator.paginate_queryset(queryset, self.request, view=self) def get_paginated_response(self, data): + """ + Return a paginated style `Response` object for the given output data. + """ + assert self.paginator is not None return self.paginator.get_paginated_response(data) -- cgit v1.2.3