Beego中多条件筛选必须先调用QueryTable获取QuerySeter,再链式调用Filter/Exclude;每次调用返回新QuerySeter,需赋值接收,支持__gt、__in等表达式,空值需预判,复杂OR逻辑才用Raw()。

QueryTable 之后才能链式拼接 Filter / Exclude
Beego ORM 的动态条件拼接,核心是依赖 QuerySeter 对象的链式调用能力。但必须先通过 QueryTable() 获取查询入口,否则直接对 Orm 实例调用 Filter() 会报错(undefined method Filter)。
常见错误现象:写成 o.Filter("name", "a").All(&list) —— 这完全无效,Orm 对象本身不支持条件方法。
正确起点只有这三种之一:
-
o.QueryTable("user")(字符串表名) -
o.QueryTable(&User{})(空结构体实例) -
o.QueryTable(new(User))(指针类型)
拿到 QuerySeter 后,每个 Filter() 或 Exclude() 都返回一个新的 QuerySeter,所以可以安全地按需追加。
用变量控制是否添加某个 Filter 条件
动态拼接的本质,就是把条件判断逻辑放在 Filter() 调用之前。不能“先拼 SQL 字符串”,而是靠 Go 的 if 分支决定是否执行某次链式调用。
例如:前端传参 name 和 age_gt,只在非空/有效时才加入条件:
qs := o.QueryTable(&User{})
if name != "" {
qs = qs.Filter("name__icontains", name)
}
if age_gt > 0 {
qs = qs.Filter("age__gt", age_gt)
}
err := qs.All(&users)
注意:qs = qs.Filter(...) 是必须的赋值,因为每次调用都返回新对象,原 qs 不变。漏掉赋值等于白加条件。
容易踩的坑:
- 误用
qs.Filter(...)却不接收返回值 → 条件丢失 - 把字符串拼成
"name__icontains=" + name再传给Filter()→ 语法错误,Filter()第二个参数是值,不是完整表达式 - 对数字字段传字符串(如
Filter("age", "25"))→ MySQL 可能隐式转换,PostgreSQL 直接报错invalid input syntax for integer
多个字段的 in 查询要传 slice,不能传逗号字符串
当需要动态构造 IN 条件(比如选中多个用户 ID),Filter("id__in", ids...) 中的 ids 必须是切片,且要用 ... 展开。
错误写法:Filter("id__in", "1,2,3") → 查的是字符串字面量 '1,2,3',不是三个整数。
正确写法:
var ids []int
if len(idStrs) > 0 {
for _, s := range idStrs {
if i, err := strconv.Atoi(s); err == nil {
ids = append(ids, i)
}
}
}
if len(ids) > 0 {
qs = qs.Filter("id__in", ids...)
}
性能影响:如果 ids 过长(比如上千个),MySQL 可能触发 max_allowed_packet 限制;PostgreSQL 对 IN 列表长度无硬限制,但过长会影响计划器选择索引。建议超过 500 项时改用临时表或分批查询。
RelatedSel 关联查询不能动态控制字段,但可动态开关关联本身
RelatedSel() 本身不支持传入字段白名单,它只控制是否 JOIN 关联表。想“动态查 user.name 但不查 user.email”,只能靠 All(..., "name") 指定主表字段,而关联字段始终全量加载(除非手动写 Raw)。
但你可以动态决定是否启用关联:
qs := o.QueryTable(&Article{})
if needUser {
qs = qs.RelatedSel("user") // 加 JOIN
}
// 注意:RelatedSel() 必须在 All()/One() 前调用,且不能多次调用同一字段
err := qs.All(&articles, "title", "content")
容易被忽略的点:
-
RelatedSel("user")中的"user"是 struct 字段名(小写),不是数据库表名或模型名 - 如果模型里定义了多个 rel 字段(如
User和Category),可以分别调用RelatedSel("user").RelatedSel("category"),但顺序不影响 SQL - 一旦用了
RelatedSel(),即使你All(..., "title"),关联表字段仍会全部查出(只是没赋值到 struct 字段),这点和 GORM 的Select()行为不同


















