Filter() 每次返回新 QuerySeter,必须链式调用;空值不自动跳过,需手动判空;双下划线语法不可省略;所有条件为 AND,OR 需用 Raw()。

Filter() 不是“链式构建器”,每次调用都返回新 QuerySeter,必须连续接续,否则条件丢失。
Filter() 必须链式调用,不能分多行赋值
Beego 的 Filter() 每次执行都会返回一个新的 QuerySeter,原对象不变。写成两行就等于只用了最后一个条件:
qs := o.QueryTable("user")
qs.Filter("status", 1) // ❌ 这行没保存返回值,白执行
qs.Filter("created__gte", "2024-01-01") // ❌ 只有这行生效
正确写法只能是单行链式:
qs := o.QueryTable("user").Filter("status", 1).Filter("created__gte", "2024-01-01")- 所有
Filter()、Exclude()、Limit()都得串在一条表达式里 - 如果逻辑复杂,建议用变量承接中间结果:
qs = qs.Filter("name__icontains", name)
空值和零值不会被自动跳过,必须手动过滤
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", age) } - 布尔字段尤其危险:
Filter("is_deleted", false)查的是显式为false的记录,不是“未删除”;真要查未删除应留空或用Exclude("is_deleted", true)
双下划线 __ 是固定语法,不能省略或写错
所有操作符和嵌套字段都依赖 __ 分隔,写成单下划线或空格会静默失败(生成的 SQL 条件直接消失)。
- 正确:
"created__gte"、"profile__city__icontains"、"status__in" - 错误:
"created_gte"、"profile.city__icontains"、"status_in" - 外键关联字段也一样:
"ArticleType__TypeName"中两个__缺一不可 - 大小写不敏感操作符以
i开头,如"name__istartswith",不是"name__startwithi"
OR 或嵌套逻辑无法用 Filter() 实现,必须退到 Raw()
Filter() 所有条件之间全是 AND,不支持 OR、括号分组、混合 NOT。比如 “名字含 a 或标题含 a” 就没法写。
- 别拼字符串:
Raw("WHERE name LIKE '%" + kw + "%' OR title LIKE '%" + kw + "%'")❌ 易 SQL 注入 - 用占位符:
o.Raw("SELECT * FROM post WHERE name LIKE ? OR title LIKE ?", "%"+kw+"%", "%"+kw+"%").QueryRows(&posts) - 想复用 ORM 结构体?先
Raw()查 ID 列表,再QueryTable("post").Filter("id__in", idList)二次加载 -
FilterChain是过时/非官方方案,文档无支持,别浪费时间
最常被忽略的一点:Filter() 的执行顺序不影响 SQL 语义(AND 无序),但影响空值判断的先后——如果前面一个条件因空值被跳过,后面条件仍可能因未校验而误入。动态条件务必统一收口做判空,而不是靠“哪个 Filter 写在前面”。











