Manager方法返回未执行的QuerySet以支持链式调用,语义清晰且便于维护;应避免在其中执行IO、计算或提前求值,确保全程惰性求值并正确使用self.filter()。

因为这些方法把重复的查询条件封装成可调用的接口,直接挂在模型上,哪里要用就点哪里,不用每次手写 filter()、exclude() 或拼 Q 对象。
Manager方法本质是链式查询集的起点
自定义的 active()、published() 这类方法返回的不是数据列表,而是未执行的 QuerySet。这意味着你可以继续接 .order_by()、.select_related(),甚至再套一层自定义方法:
- 它不是“执行完就吐结果”的函数,而是“搭好SQL架子等你加料”的构造器
- 所以
Article.published().order_by('-pub_date')和Article.objects.filter(is_published=True).order_by('-pub_date')生成的 SQL 完全一致,但前者语义清晰、不易出错 - 如果某天业务规则变更为“已发布且非草稿”,只需改
PublishedManager里一个地方,所有调用自动生效
和类方法、模块函数比,Manager天然绑定模型上下文
你在视图、管理命令、信号处理里用 Article.published.all(),不需要 import 额外模块,也不用传模型类进去——它已经知道操作的是 Article:
- 类方法(如
@classmethod def get_published(cls))要显式写cls.objects.filter(...),容易误用成cls.objects.all()后再 filter,绕过 manager 逻辑 - 普通函数(如
get_published_articles())得手动传model=Article或硬编码模型名,跨应用复用时路径易错、迁移难 - Manager 实例在模型定义时就挂载好,Django 自动注入,IDE 也能正确补全
published.后的方法
容易踩的坑:别在 Manager 方法里做计算或 IO
Manager 方法应该只负责“描述查询”,而不是“执行副作用”。常见翻车点:
立即学习“Python免费学习笔记(深入)”;
- 在
def active(self)里调用cache.get()或发 HTTP 请求 → 查询还没执行就被卡住,且无法链式调用 - 返回
list(self.filter(...))而不是self.filter(...)→ 失去惰性求值能力,.count()变成内存遍历 - 方法里用了
self.model.objects.filter(...)而不是self.filter(...)→ 绕过当前 manager 实例,可能漏掉子类重写的 manager 行为 - 抽象基类里直接定义
objects = CustomManager()→ 所有继承它的子模型共享同一个 manager 实例,字段感知失效(比如子类新加了status字段,manager 却不知道)
真正关键的不是“写了方法”,而是方法返回的必须是未求值的 QuerySet,且全程不脱离 ORM 的链式构建机制。否则看似复用,实则埋下 N+1、缓存错乱、测试难 mock 的隐患。


















