Skip to content

Instantly share code, notes, and snippets.

@sartim
Last active April 29, 2020 14:43
Show Gist options
  • Save sartim/267f825cb48aca86a8c33780c9801f60 to your computer and use it in GitHub Desktop.
Save sartim/267f825cb48aca86a8c33780c9801f60 to your computer and use it in GitHub Desktop.
SQLAlchemy Pagination In Flask
import os
from math import ceil
from flask import abort, request
class Pagination:
def __init__(self, query=None, page=None, per_page=None, total=None, items=None):
self.query = query
self.page = page
self.per_page = per_page
self.total = total
self.items = items
@property
def pages(self):
if self.per_page == 0 or self.total is None:
pages = 0
else:
pages = int(ceil(self.total / float(self.per_page)))
return pages
def prev(self, error_out=False):
assert self.query is not None, 'a query object is required ' \
'for this method to work'
return self.query.paginate(self.page - 1, self.per_page, error_out)
@property
def prev_num(self):
if not self.has_prev:
return None
return self.page - 1
@property
def has_prev(self):
return self.page > 1
def next(self, error_out=False):
assert self.query is not None, 'a query object is required ' \
'for this method to work'
return self.query.paginate(self.page + 1, self.per_page, error_out)
@property
def has_next(self):
return self.page < self.pages
@property
def next_num(self):
if not self.has_next:
return None
return self.page + 1
def iter_pages(self, left_edge=2, left_current=2,
right_current=5, right_edge=2):
last = 0
for num in range(1, self.pages + 1):
if num <= left_edge or \
(self.page - left_current - 1 < num < self.page + right_current) or \
num > self.pages - right_edge:
if last + 1 != num:
yield None
yield num
last = num
@classmethod
def paginate(cls, obj=None, page=None, per_page=None, error_out=True, max_per_page=None, count=True):
""":param obj: Query Object E.g User.query"""
if obj:
if request:
if page is None:
try:
page = int(request.args.get('page', 1))
except (TypeError, ValueError):
if error_out:
abort(404)
page = 1
if per_page is None:
try:
per_page = int(request.args.get('per_page', 20))
except (TypeError, ValueError):
if error_out:
os.abort(404)
per_page = 20
else:
if page is None:
page = 1
if per_page is None:
per_page = 20
if max_per_page is not None:
per_page = min(per_page, max_per_page)
if page < 1:
if error_out:
abort(404)
else:
page = 1
if per_page < 0:
if error_out:
abort(404)
else:
per_page = 20
items = obj.limit(per_page).offset((page - 1) * per_page).all()
if not items and page != 1 and error_out:
abort(404)
if not count:
total = None
elif page == 1 and len(items) < per_page:
total = len(items)
else:
total = obj.order_by(None).count()
return Pagination(obj, page, per_page, total, items)
return None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment