import flask from flask_paginate import Pagination from werkzeug.utils import cached_property class QueryPagination(Pagination): """ Customized flask-pagination paginator. Updated default params and added some shortcuts for qs logic. """ PER_PAGE_OPTIONS = (10, 20, 30) def __init__( self, inner_window=2, outer_window=0, display_msg="Showing {start} - {end} of {total} results", prev_label='', next_label='', css_framework="bootstrap3", **kwargs, ): self.per_page_options = ( kwargs.pop("per_page_options", None) or self.PER_PAGE_OPTIONS ) total = kwargs.pop("total", 0) self.query = kwargs.pop("query", None) if self.query is not None: try: total = self.query.count() except TypeError: total = len(self.query) found = total if kwargs.get("search") else 0 else: found = 0 super().__init__( found=found, inner_window=inner_window, outer_window=outer_window, display_msg=display_msg, prev_label=prev_label, next_label=next_label, total=total, css_framework=css_framework, **kwargs, ) @property def items(self): if self.query: return self.query.paginate(self.page, self.per_page).items return [] def __eq__(self, other): try: return self.items == other.items except AttributeError: return False @property def per_page_args(self): all_args = {**flask.request.view_args, **flask.request.args} return { k: v for k, v in all_args.items() if k not in (self.page_parameter, self.per_page_parameter) } @property def go_to_page_params(self): return { k: v for k, v in flask.request.args.items() if k != self.page_parameter } class APIQueryPagination: """ Limit/offset paginator. Paginates query with explicitly passed limit/offset params or HTTP GET retrieved params. """ DEFAULT_LIMIT = 100 MAX_LIMIT = 1000 def __init__(self, query, limit=None, offset=None): self._query = query self.limit = limit or flask.request.args.get( "limit", default=self.DEFAULT_LIMIT, type=int ) self.limit = self.limit if self.limit >= 0 else self.DEFAULT_LIMIT self.limit = min(self.limit, self.MAX_LIMIT) self.offset = offset or flask.request.args.get( "offset", default=0, type=int ) self.offset = max(self.offset, 0) def __eq__(self, other): try: return self.items == other.items except AttributeError: return False @property def items(self): return self.query.all() @property def query(self): return self._query.limit(self.limit).offset(self.offset) @cached_property def count(self): return self._query.count() @property def previous(self): if self.offset > 0: args = flask.request.args.copy() args["offset"] = max(self.offset - self.limit, 0) return flask.url_for( flask.request.endpoint, **flask.request.view_args, **args ) @property def next(self): if self.offset + 1 < self.count and self.count > self.limit: args = flask.request.args.copy() args["offset"] = self.offset + self.limit return flask.url_for( flask.request.endpoint, **flask.request.view_args, **args )