From 0e85351fbd5b8f8d4eb610a4c40505d884b5d551 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 15 Jun 2016 11:49:07 -0700 Subject: [PATCH] Initial setup --- .gitignore | 6 ++ LICENSE | 20 ++++++ README.md | 8 +++ drf-ember-pagination/__init__.py | 0 drf-ember-pagination/pagination.py | 98 ++++++++++++++++++++++++++++++ requirements.txt | 1 + setup.py | 20 ++++++ 7 files changed, 153 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 drf-ember-pagination/__init__.py create mode 100644 drf-ember-pagination/pagination.py create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52925c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.py[cod] +*.py[cod] +*.pyc +__pycache__ +.env +venv diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..71566bd --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2016 Matthew R. Dillon + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3184bf --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# drf-ember-pagination + +Provides a custom DRF pagination class for consumption in some of my ember applications + +## Contact + +Do you have an idea for a feature? Find a bug? +Reach me at [matthewrdillon@gmail.com](mailto:matthewrdillon@gmail.com) diff --git a/drf-ember-pagination/__init__.py b/drf-ember-pagination/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/drf-ember-pagination/pagination.py b/drf-ember-pagination/pagination.py new file mode 100644 index 0000000..28d8714 --- /dev/null +++ b/drf-ember-pagination/pagination.py @@ -0,0 +1,98 @@ +""" + Most of this is pulled directly from DRF, with minor tweaks. +""" + +from collections import OrderedDict, namedtuple + +from rest_framework import pagination +from rest_framework.response import Response +from rest_framework.utils.urls import remove_query_param, replace_query_param + + +def _get_displayed_page_numbers(current, final): + """ + This utility function determines a list of page numbers to display. + This gives us a nice contextually relevant set of page numbers. + For example: + current=14, final=16 -> [1, None, 13, 14, 15, 16] + This implementation gives one page to each side of the cursor, + or two pages to the side when the cursor is at the edge, then + ensures that any breaks between non-continous page numbers never + remove only a single page. + For an alernativative implementation which gives two pages to each side of + the cursor, eg. as in GitHub issue list pagination, see: + https://gist.github.com/tomchristie/321140cebb1c4a558b15 + """ + assert current >= 1 + assert final >= current + + if final <= 5: + return list(range(1, final + 1)) + + # We always include the first two pages, last two pages, and + # two pages either side of the current page. + included = {1, current - 1, current, current + 1, final} + + # If the break would only exclude a single page number then we + # may as well include the page number instead of the break. + if current <= 4: + included.add(2) + included.add(3) + if current >= final - 3: + included.add(final - 1) + included.add(final - 2) + + # Now sort the page numbers and drop anything outside the limits. + included = [ + idx for idx in sorted(list(included)) + if idx > 0 and idx <= final + ] + + # Finally insert any `...` breaks + if current > 4: + included.insert(1, None) + if current < final - 3: + included.insert(len(included) - 1, None) + return included + + +def _get_page_links(page_numbers, current): + """ + Given a list of page numbers and `None` page breaks, + return a list of `PageLink` objects. + """ + page_links = [] + for page_number in page_numbers: + if page_number is None: + page_link = { + 'number': None, + 'is_active': False, + 'is_break': True, + } + else: + page_link = { + 'number': page_number, + 'is_active': (page_number == current), + 'is_break': False, + } + page_links.append(page_link) + return page_links + + +class CustomPageNumberPagination(pagination.PageNumberPagination): + page_size_query_param = 'page_size' + + def get_paginated_response(self, data): + base_url = self.request.build_absolute_uri() + current = self.page.number + final = self.page.paginator.num_pages + page_numbers = _get_displayed_page_numbers(current, final) + page_links = _get_page_links(page_numbers, current) + + return Response(OrderedDict([ + ('count', self.page.paginator.count), + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('pagination', page_links), + ('results', data), + ])) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..92fd45b --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +djangorestframework>=3.3.2 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c8dbdcd --- /dev/null +++ b/setup.py @@ -0,0 +1,20 @@ +from setuptools import setup, find_packages + + +with open('README.md') as f: + readme = f.read() + +with open('LICENSE') as f: + license = f.read() + +setup( + name='drf-ember-pagination', + version='0.1.0', + description='Custom pagination class for ember applications', + long_description=readme, + author='Matthew Ryan Dillon', + author_email='matthewrdillon@gmail.com', + url='https://github.com/thermokarst/drf-ember-pagination', + license=license, + packages=find_packages(exclude=('tests', 'docs')) +)