]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger |
2 | from rest_framework.exceptions import ParseError | |
3 | from rest_framework.pagination import PaginationSerializer | |
4 | ||
5 | ||
6 | class PaginatedMixin(object): | |
7 | default_page_size = 10 | |
8 | ||
9 | @property | |
10 | def _pagination_serializer(self): | |
11 | if not hasattr(self, '__pagination_serializer'): | |
12 | class LocalPaginationSerializer(PaginationSerializer): | |
13 | class Meta: | |
14 | object_serializer_class = self.serializer_class | |
15 | ||
16 | self.__pagination_serializer = LocalPaginationSerializer | |
17 | return self.__pagination_serializer | |
18 | ||
19 | def _paginate(self, request, objects): | |
20 | # Pagination is, of course, separate to databaseyness, so you might think | |
21 | # to put this in a different mixin. However, the *way* you do pagination | |
22 | # with LIMIT et al is rather coupled to the database, so here we are. | |
23 | ||
24 | page_number = request.GET.get('page', 1) | |
25 | page_size = request.GET.get('page_size', self.default_page_size) | |
26 | ||
27 | # The django paginator conveniently works for sqlalchemy querysets because | |
28 | # they both have .count() and support array slicing | |
29 | try: | |
30 | paginator = Paginator(objects, page_size) | |
31 | page = paginator.page(page_number) | |
32 | except (ValueError, EmptyPage, PageNotAnInteger) as e: | |
33 | # Raise 400 is 'page' or 'page_size' were bad | |
34 | raise ParseError(str(e)) | |
35 | ps = self._pagination_serializer(instance=page, context={'request': request}) | |
36 | return ps.data |