beego 的 paginator 必须在 controller 的 http 方法中初始化并传入模板,如 p := paginator.new(20, totalcount) 且需通过 this.data["paginator"] = p 传递;模板中须判空使用 {{if .paginator}},url 参数需手动保留, totalcount 不可为 0。

Beego 的 Paginator 类怎么用才不报错
Beego 自带的 Paginator 是最轻量的分页方案,但它不是开箱即用——你得手动传入总记录数和每页条数,且必须在 Controller 中初始化后显式传给模板。常见错误是直接在模板里调用 .Paginater() 却没在控制器中创建实例,导致模板渲染时报 nil pointer dereference。
实操要点:
-
Paginator必须在Get()或其他 HTTP 方法内初始化,例如:p := paginator.New(20, totalCount),其中20是每页数量,totalCount需提前查出(不能传0) - 必须通过
this.Data["Paginator"] = p传入模板,模板中才能用{{.Paginator}} - 它不自动处理 URL 参数,当前页码靠
this.Input().Get("p")获取,默认值建议设为"1",并转成int再传给New() - 注意:Beego 2.x 中
paginator已移至github.com/beego/beego/v2/utils/pagination,旧 import 路径会编译失败
SQL 查询如何配合分页避免全表扫描
只靠 Paginator 控制显示逻辑远远不够。如果每次请求都查全表再用 Limit/Offset 截取,数据量一大就卡死。关键是要让数据库只返回当前页需要的数据。
实操建议:
- 先执行一次
COUNT(*)获取总记录数(用于初始化Paginator),再执行带LIMIT和OFFSET的主查询 - 用
OFFSET分页在大数据集下性能差,可改用「游标分页」:按主键或时间戳排序,用WHERE id > ? LIMIT 20替代OFFSET;但 Beego 本身不提供游标封装,需自行拼 SQL 或用 ORM 的QueryTable().Filter() - 如果用了
orm.QueryTable("user").Limit(20).Offset(40),确保Offset值已校验为非负整数,否则 ORM 可能静默忽略或 panic
模板里怎么安全渲染分页 HTML
Beego 的 Paginator 提供了 .PageNums、.IsFirstPage、.IsLastPage 等字段,但直接写 {{range .Paginator.PageNums}} 容易因空指针崩溃——当总数为 0 或参数异常时,.PageNums 可能为 nil。
推荐写法(在模板中):
{{if .Paginator}}
{{if .Paginator.PageNums}}
{{range .Paginator.PageNums}}
{{if eq . $.Paginator.Current}}
<span class="current">{{.}}</span>
{{else}}
<a href="https://www.php.cn/link/b02d27666964db9258b673accd36c27a">{{.}}</a>
{{end}}
{{end}}
{{end}}
{{end}}
额外注意:
-
.Paginator.Current返回的是当前页码(int),但模板中比较必须用eq,不能写== - 上一页/下一页链接要判断边界:
{{if .Paginator.IsPrev}}和{{if .Paginator.IsNext}} - URL 参数不止
p时(比如带搜索关键词),不能硬写?p=2,得用urlfor或拼接现有 query string
为什么分页跳转后搜索条件丢了
这是最常被忽略的耦合点:分页本质是状态迁移,而 Beego 默认只认 p 参数。如果列表支持搜索,用户翻页时 URL 里的 q=xxx 会丢失,导致第二页查的是全量数据。
解决思路不是改 Beego 源码,而是控制链接生成逻辑:
- 在 Controller 中把所有非分页参数存进
this.Data["QueryParams"],例如:this.Data["QueryParams"] = this.Input().QueryString()(注意过滤掉p) - 模板中构造链接时,用
{{.QueryParams}}拼接:<a href="https://www.php.cn/link/b02d27666964db9258b673accd36c27a&%7B%7B.QueryParams%7D%7D"></a> - 更健壮的做法是用 Go 函数预处理参数,比如写个
buildPageURL(page int)返回完整 URL 字符串,再传给模板
分页看着简单,真正落地时,数据库查询、URL 状态保持、模板空值防护这三处最容易漏掉校验。别指望框架替你记住搜索条件,也别在没查总数前就初始化 Paginator。











