Flask中paginate()分页必须显式传入int型page和业务指定的per_page,否则默认page=1、per_page=20易致翻页404或数据异常;应强制type=int转换、限制per_page范围,并善用.items、.pages、.has_next等内置属性简化分页逻辑。

Flask 中用 paginate() 做分页,必须传 page 和 per_page
不传或传错参数,paginate() 会默认 page=1、per_page=20,但你很可能没意识到——结果就是第一页数据永远对,翻页后 404 或返回空列表,还查不出原因。
常见错误现象:request.args.get('page', 1, type=int) 没加 type=int,导致传入字符串 "2",paginate() 内部类型校验失败,静默 fallback 到 page=1;或者漏传 per_page,依赖默认值,上线后发现每页突然显示 20 条而非预期的 10 条。
- 务必从请求中显式提取
page,并强制转为int,default=1是安全底线 -
per_page不要依赖默认值,业务层应明确控制(比如固定 10,或从配置读取) - 如果允许前端指定
per_page,需加范围限制(如 1–100),避免per_page=10000直接拖垮数据库
paginate() 返回对象里哪些字段真正有用
很多人只用 .items,却忽略 .pages、.has_next 这些字段,结果模板里写一堆逻辑判断当前页、总页数、是否禁用“下一页”按钮——其实都白搭,paginate() 全给你算好了。
使用场景:渲染分页导航栏、判断是否显示“上一页/下一页”、做 API 分页响应头(如 X-Total-Pages)。
立即学习“Python免费学习笔记(深入)”;
-
.items:当前页的数据列表(已经是 Python list,不是 Query 对象) -
.page和.pages:当前页码、总页数,比手动ceil(total / per_page)更可靠(尤其最后一页不满时) -
.has_prev/.has_next:布尔值,比page > 1或page 更准确(考虑了无数据时 <code>pages=0的边界) -
.prev_num/.next_num:直接可用的页码数字,不用再加减 1
SQLAlchemy paginate() 在不同版本行为差异大
2.0+ 版本的 paginate() 默认启用 error_out=True,页码超出范围直接抛 NotFound 异常;而 1.4 默认是 error_out=False,返回空 .items 且 .pages=0。不留意这点,升级 SQLAlchemy 后分页接口全崩成 404。
性能影响:2.0+ 默认还会执行额外 COUNT 查询来算总页数,如果你只用“下一页”按钮(不需要总页数),可关掉:paginate(..., count=False),省一次 COUNT。
- 显式指定
error_out=False可统一行为,避免版本升级引发线上问题 - 若确定不会访问非法页码(比如前端禁用跳转输入框),
count=False能明显降低小表分页延迟 - 注意:关掉
count后,.pages、.total就不可用了,.has_next仍有效(靠是否查到per_page + 1条判断)
模板里别手写分页 URL,用 url_for() 动态构造
硬编码 /users?page=2 看似简单,但一旦路由带参数(如 /admin/users?role=admin&page=2),或 Flask 配置了 URL_PREFIX,就全乱套。更糟的是,有人把 request.args 全拼进 URL,结果把敏感参数(如 token)也透出去了。
正确做法是只保留分页相关参数,其他过滤掉。Flask 自带的 request.args.to_dict() 是起点,但得手动剔除非分页键。
- 在视图函数里提前整理好分页上下文:
pagination = query.paginate(...); pagination_args = {'page': pagination.page, 'per_page': pagination.per_page} - 模板中用
{{ url_for('user_list', **pagination_args) }},干净又可靠 - 如果路由本身有变量(如
@app.route('/blog/<category_id>')</category_id>),记得把category_id也传进url_for()
page 类型、error_out 默认值、count 开关、URL 构造这四点,任一出错都会让分页逻辑在某个边界条件下悄无声息地失效。










