beego orm分页需手动组合limit()和offset(),无内置paginate方法;核心为offset=(page-1)*pagesize,且limit必须在offset之后调用;须校验page≥1、limit∈(0,100],count()独立执行,前端需手动组装分页元信息。

Beego 中用 orm.QuerySeter.Limit() 和 orm.QuerySeter.Offset() 做分页
Beego 的 ORM 分页不是靠一个函数自动完成的,必须手动组合 Limit() 和 Offset()。很多人误以为有 Paginate() 这类方法,实际没有——直接调用会报 undefined method 错误。
核心逻辑是:当前页码 page(从 1 开始)、每页条数 pageSize → 计算 Offset = (page - 1) * pageSize,再链式调用:
qs := orm.NewOrm().QueryTable(&User{})
total, _ := qs.Count()
qs.Limit(pageSize).Offset((page - 1) * pageSize).All(&users)
-
Limit()必须在Offset()之后调用才生效(Beego ORM v1.x 的执行顺序敏感) - 如果
page是用户传入的字符串(如 URL 参数),务必先用strconv.Atoi()转换并校验是否 > 0,否则Offset(-1)会导致查出全部数据 -
Count()不受Limit/Offset影响,可放心前置调用
分页参数校验和默认值怎么设才安全
URL 里常见 ?page=1&limit=20,但用户可能传 page=abc、limit=-10 或干脆不传。Beego 没有内置参数绑定校验,得自己兜底。
- 用
this.GetString("page")和this.GetString("limit")取值,空值时设默认page = 1、limit = 10 -
limit建议硬限制上限(如 100),防止恶意请求拖垮数据库:if limit > 100 { limit = 100 } - 计算
offset前检查page ,直接返回空结果或重定向,别让 ORM 执行非法偏移
前端需要的分页元信息怎么组装
光查出数据不够,前端分页控件要总页数、当前页、是否有上/下一页。这些得手动生成 JSON 返回,Beego 不提供现成结构体。
典型响应结构:
{
"data": [...],
"pagination": {
"total": 127,
"page": 2,
"page_size": 20,
"total_pages": 7,
"has_prev": true,
"has_next": true
}
}
-
total_pages = int(math.Ceil(float64(total) / float64(limit))),注意用math.Ceil避免整除丢页 -
has_prev = page > 1,has_next = page ,比查两次数据库更轻量 - 别把
total省略——有些场景(如搜索)需要动态显示“共 X 条结果”
为什么不能用 Raw() 写 LIMIT ?OFFSET 就完事
能写,但不推荐。原生 SQL 分页在 MySQL 和 PostgreSQL 语法不同(PostgreSQL 用 OFFSET ... LIMIT,MySQL 是 LIMIT ..., ...),而 Beego ORM 的 Limit()/Offset() 会自动适配驱动。
- 用
Raw()失去 ORM 的模型映射能力,查出来是[]map[string]interface{},还得手动转结构体 - SQL 注入风险更高:如果拼接了未过滤的
page参数,Raw("SELECT * FROM user LIMIT " + limit)极易中招 - 事务、Preload 关联查询等高级功能无法与
Raw()兼容
除非你明确需要窗口函数或复杂子查询分页,否则坚持用 QuerySeter 链式调用更稳。











