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
)