diff --git a/flask_sqlalchemy/__init__.py b/flask_sqlalchemy/__init__.py index 520afa00..a2b55637 100644 --- a/flask_sqlalchemy/__init__.py +++ b/flask_sqlalchemy/__init__.py @@ -325,7 +325,7 @@ def __init__(self, query, page, per_page, total, items): @property def pages(self): """The total number of pages""" - if self.per_page == 0: + if self.per_page == 0 or self.total is None: pages = 0 else: pages = int(ceil(self.total / float(self.per_page))) @@ -427,13 +427,14 @@ def first_or_404(self): abort(404) return rv - def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None): + def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None, count=True): """Returns ``per_page`` items from page ``page``. If ``page`` or ``per_page`` are ``None``, they will be retrieved from the request query. If ``max_per_page`` is specified, ``per_page`` will be limited to that value. If there is no request or they aren't in the - query, they default to 1 and 20 respectively. + query, they default to 1 and 20 respectively. If ``count`` is ``False``, + no query to help determine total page count will be run. When ``error_out`` is ``True`` (default), the following rules will cause a 404 response: @@ -494,8 +495,11 @@ def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None): abort(404) # No need to count if we're on the first page and there are fewer - # items than we expected. - if page == 1 and len(items) < per_page: + # items than we expected or if count is disabled. + + if not count: + total = None + elif page == 1 and len(items) < per_page: total = len(items) else: total = self.order_by(None).count() diff --git a/tests/test_pagination.py b/tests/test_pagination.py index 05621c71..74dd4dd1 100644 --- a/tests/test_pagination.py +++ b/tests/test_pagination.py @@ -22,6 +22,11 @@ def test_pagination_pages_when_0_items_per_page(): assert p.pages == 0 +def test_pagination_pages_when_total_is_none(): + p = fsa.Pagination(None, 1, 100, None, []) + assert p.pages == 0 + + def test_query_paginate(app, db, Todo): with app.app_context(): db.session.add_all([Todo('', '') for _ in range(100)]) @@ -68,3 +73,11 @@ def test_paginate_min(app, db, Todo): with pytest.raises(NotFound): Todo.query.paginate(per_page=-1) + + +def test_paginate_without_count(app, db, Todo): + with app.app_context(): + db.session.add_all(Todo('', '') for _ in range(20)) + db.session.commit() + + assert len(Todo.query.paginate(count=False, page=1, per_page=10).items) == 10