Skip to content

Commit 49ecc8c

Browse files
authored
Merge pull request pallets-eco#558 from davidism/no_negative_offset
set page and per_page defaults when invalid
2 parents d7cc392 + c61919d commit 49ecc8c

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ In development
1616
flushed yet. (`#555`_)
1717
- Allow specifying a ``max_per_page`` limit for pagination, to avoid users
1818
specifying high values in the request args. (`#542`_)
19+
- For ``paginate`` with ``error_out=False``, the minimum value for ``page`` is
20+
1 and ``per_page`` is 0. (`#558`_)
1921

2022
.. _#542: https://github.com/mitsuhiko/flask-sqlalchemy/pull/542
2123
.. _#551: https://github.com/mitsuhiko/flask-sqlalchemy/pull/551
2224
.. _#555: https://github.com/mitsuhiko/flask-sqlalchemy/pull/555
2325
.. _#556: https://github.com/mitsuhiko/flask-sqlalchemy/pull/556
26+
.. _#558: https://github.com/mitsuhiko/flask-sqlalchemy/pull/558
2427

2528

2629
Version 2.3.0

flask_sqlalchemy/__init__.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -430,16 +430,20 @@ def first_or_404(self):
430430
def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None):
431431
"""Returns ``per_page`` items from page ``page``.
432432
433-
If no items are found and ``page`` is greater than 1, or if page is
434-
less than 1, it aborts with 404.
435-
This behavior can be disabled by passing ``error_out=False``.
436-
437433
If ``page`` or ``per_page`` are ``None``, they will be retrieved from
438-
the request query.
439-
If the values are not ints and ``error_out`` is ``True``, it aborts
440-
with 404.
441-
If there is no request or they aren't in the query, they default to 1
442-
and 20 respectively.
434+
the request query. If ``max_per_page`` is specified, ``per_page`` will
435+
be limited to that value. If there is no request or they aren't in the
436+
query, they default to 1 and 20 respectively.
437+
438+
When ``error_out`` is ``True`` (default), the following rules will
439+
cause a 404 response:
440+
441+
* No items are found and ``page`` is not 1.
442+
* ``page`` is less than 1, or ``per_page`` is negative.
443+
* ``page`` or ``per_page`` are not ints.
444+
445+
When ``error_out`` is ``False``, ``page`` and ``per_page`` default to
446+
1 and 20 respectively.
443447
444448
Returns a :class:`Pagination` object.
445449
"""
@@ -472,8 +476,17 @@ def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None):
472476
if max_per_page is not None:
473477
per_page = min(per_page, max_per_page)
474478

475-
if error_out and page < 1:
476-
abort(404)
479+
if page < 1:
480+
if error_out:
481+
abort(404)
482+
else:
483+
page = 1
484+
485+
if per_page < 0:
486+
if error_out:
487+
abort(404)
488+
else:
489+
per_page = 20
477490

478491
items = self.limit(per_page).offset((page - 1) * per_page).all()
479492

tests/test_pagination.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import pytest
2+
from werkzeug.exceptions import NotFound
3+
14
import flask_sqlalchemy as fsa
25

36

@@ -49,3 +52,19 @@ def test_query_paginate_more_than_20(app, db, Todo):
4952
db.session.commit()
5053

5154
assert len(Todo.query.paginate(max_per_page=10).items) == 10
55+
56+
57+
def test_paginate_min(app, db, Todo):
58+
with app.app_context():
59+
db.session.add_all(Todo(str(x), '') for x in range(20))
60+
db.session.commit()
61+
62+
assert Todo.query.paginate(error_out=False, page=-1).items[0].title == '0'
63+
assert len(Todo.query.paginate(error_out=False, per_page=0).items) == 0
64+
assert len(Todo.query.paginate(error_out=False, per_page=-1).items) == 20
65+
66+
with pytest.raises(NotFound):
67+
Todo.query.paginate(page=0)
68+
69+
with pytest.raises(NotFound):
70+
Todo.query.paginate(per_page=-1)

0 commit comments

Comments
 (0)