Beego ORM 的 Filter() 每次返回新 QuerySeter,必须链式调用;空值不会自动跳过,需手动判断;不支持 OR 和嵌套逻辑,复杂查询需用 Raw();字段与操作符间须用双下划线。

Filter() 每次都返回新 QuerySeter,链式调用不是可选,是必须
Beego ORM 的 Filter() 不是“在原对象上追加条件”,而是每次调用都生成一个全新 QuerySeter。写成两行就等于只用了最后一个条件:
qs := o.QueryTable("user")
qs.Filter("status", 1) // ❌ 这行执行完,返回的新 qs 没被接收
qs.Filter("created__gte", t) // ❌ 只有这行生效
正确写法必须链式接续:
qs := o.QueryTable("user").Filter("status", 1).Filter("created__gte", t)- 中间不能断开赋值,也不能复用旧
qs变量覆盖前序条件 - 如果条件数不确定(比如表单筛选),建议用变量承接每一步:
qs = qs.Filter(...)
空值和零值不会被自动跳过,必须手动 guard
用户提交 age=0、name="" 或 is_deleted=false 时,Filter("age", 0) 会查出所有 age 为 0 的记录,而不是忽略该条件 —— 这是线上误筛的高频原因。
- 字符串务必先
strings.TrimSpace()再判空:if name := strings.TrimSpace(r.FormValue("name")); name != "" { qs = qs.Filter("name__icontains", name) } - 数值类型要显式比较:
if age > 0 { qs = qs.Filter("age__gte", age) } - 布尔字段尤其危险:
Filter("is_deleted", false)查的是显式为false的行,不是“未删除”的行;真要查非删除状态,应结合Exclude("is_deleted", true)或用Filter("is_deleted__isnull", true)区分 NULL
复杂 OR / 多字段模糊匹配只能靠 Raw(),Filter() 不支持括号逻辑
当需要实现 WHERE name LIKE ? OR title LIKE ? 或嵌套条件(如 (a=1 AND b=2) OR (a=3 AND c=4))时,Filter() 完全无能为力。它只支持 AND 拼接,且不提供 OR 分组能力。
- 别拼接 SQL:
Raw("WHERE name LIKE '%" + kw + "%') ❌ - 用占位符安全传参:
o.Raw("SELECT * FROM post WHERE name LIKE ? OR title LIKE ?", "%"+kw+"%", "%"+kw+"%").QueryRows(&posts) - 若仍想走 ORM 对象映射,可先
Raw()查 ID 列表,再QueryTable("post").Filter("id__in", idList)二次加载
字段名与操作符之间必须用双下划线 __,大小写不敏感但语法严格
profile__age__gt 是合法表达式,profile_age__gt 或 profile__age_gt 都会静默失败或报错。Beego 用双下划线解析字段路径和操作符,这是硬编码规则。
- 外键关联字段写法:User 表有
ProfileId int,Profile 模型有Age int,则条件写profile__age__gt(小写字段名)或Profile__Age__gt(结构体字段名),两者都支持 - 操作符必须接在双下划线后:
name__icontains✅,name__contains❌(前者不区分大小写,后者区分,别混) - 常见漏写:
isnull后面不跟值,Filter("deleted__isnull", true)才对;Filter("deleted__isnull", nil)会 panic
实际项目里最常踩的坑不在语法,而在「以为 Filter() 会智能跳过空值」——它不会。动态组装条件时,少一次 if 判断,就可能让整个列表页返回错误数据。











