beego中应优先用querytable.filter()而非filterchain或原生sql;filter()每次返回新queryseter需链式调用,支持__gt/__in等表达式,但须预判空值、注意执行顺序,复杂or逻辑才用raw()。

Beego 中用 FilterChain 还是直接写 SQL?
别绕弯子:Beego 的 ORM 本身不提供链式多条件构建器(比如 GORM 的 Where().Where().Order()),直接拼 SQL 或用 QueryTable 的 Filter() 是主流做法。但要注意,Filter() 不是“链式调用”,而是每次调用都返回新 QuerySeter,必须连续接续,否则前一个条件就丢了。
-
Filter("name__icontains", "foo")支持字段查找符(__gt、__in、__isnull等),但注意双下划线是固定语法,不能写成单下划线 - 多个
Filter()必须串起来:qs.Filter("status", 1).Filter("created__gte", "2024-01-01"),分开写两行不生效 - 如果条件动态生成(比如用户只选了部分筛选项),建议先收集条件到 map,再循环调用
Filter(),避免空值条件污染查询
Filter() 对空值和零值的处理很危险
Beego ORM 的 Filter() 遇到空字符串 ""、零值 0、false 时不会跳过,而是当作真实条件执行——比如 Filter("age", 0) 会查出所有 age=0 的记录,而不是忽略该条件。这在表单提交中极易引发误筛。
- 务必在调用
Filter()前做显式判断:if age != 0 { qs = qs.Filter("age", age) } - 字符串类型建议用
strings.TrimSpace()后再判空:if name := strings.TrimSpace(r.FormValue("name")); name != "" { qs = qs.Filter("name__icontains", name) } - 布尔字段尤其要小心:
Filter("is_deleted", false)和Filter("is_deleted__isnull", true)完全不是一回事,前者查显式为 false 的记录,后者查 NULL 值
复杂条件(OR / 多字段模糊匹配)只能靠 Raw()
当需要 OR(name__icontains="a" OR title__icontains="a") 或嵌套括号逻辑时,Filter() 无能为力。这时候必须退回到原生 SQL,用 Raw() + 占位符,否则容易被注入或逻辑错乱。
- 不要拼接用户输入:
Raw("SELECT * FROM post WHERE name LIKE '%" + keyword + "%'")❌ - 正确写法:
o.Raw("SELECT * FROM post WHERE name LIKE ? OR title LIKE ?", "%"+kw+"%", "%"+kw+"%").QueryRows(&posts) - 如果仍想用 ORM 查询结构体,可先用
Raw()查 ID 列表,再用QueryTable("post").Filter("id__in", idList)二次加载,兼顾安全与对象映射
分页和排序必须放在 Filter() 之后
Beego 的 QuerySeter 是惰性执行,Limit()、Offset()、OrderBy() 必须在所有 Filter() 调用完成后再加,顺序反了会导致分页失效或排序不生效。
- ✅ 正确:
qs.Filter("status", 1).OrderBy("-created").Limit(10).All(&posts) - ❌ 错误:
qs.Limit(10).Filter("status", 1).All(&posts)—— 这里 Limit 会截断原始数据集,后续 Filter 在子集上操作,结果不完整 - 注意
OrderBy()参数带负号表示降序:"-created",不带是升序;多个字段用逗号分隔:"status,-created"
Beego 的多条件筛选本质是“条件累积 + 惰性执行”,最易出问题的地方不在语法,而在空值未过滤、调用顺序错乱、以及对 Filter() 返回新 QuerySeter 的误解——它不修改原对象,这点和很多 ORM 相反。











