# Django 6.0.7 documentation

# 管理器

class Manager

`Manager` 是一种接口，它赋予了 Django 模型操作数据库的能力。Django 应用中每个模型拥有至少一个 `Manager`。

`Manager` 类的文档介绍位于 执行查询；本页着重介绍自定义 `Manager` 行为的模型选项。

## 管理器名称

默认情况下，Django 为每个模型类添加了一个名为 `objects` 的 `Manager`。不过，若你想将 `objects` 用作字段名，或想使用 `objects` 以外的 `Manager` 名字，就要在模型基类中重命名。要为指定类重命名 `Manager`，在该模型中定义一个类型为 `models.Manager` 的属性。例如:

    from django.db import models

    class Person(models.Model):
        # ...
        people = models.Manager()

使用这个实例模型时， `Person.objects` 会产生一个 `AttributeError` 异常，而 `Person.people.all()` 会返回包含所有 `Person` 对象的列表。

## 自定义管理器

继承基类 `Manager`，在模型中实例化自定义 `Manager`，你就可以在该模型中使用自定义的 `Manager`。

有两种原因可能使你想要自定义 `Manager`：添加额外的 `Manager` 方法，修改 `Manager` 返回的原始 `QuerySet`。

### 添加额外的管理器方法

添加额外的 `Manager` 方法一般是为模型添加 “表级” 功能的更好方法。（对于 “行级” 功能 —— 即，只操作单个模型对象 —— 通过 模型方法，而不是自定义 `Manager` 的方法。）

例如，这个自定义的 `Manager` 添加了一个方法 `with_counts()`：

    from django.db import models
    from django.db.models.functions import Coalesce

    class PollManager(models.Manager):
        def with_counts(self):
            return self.annotate(num_responses=Coalesce(models.Count("response"), 0))

    class OpinionPoll(models.Model):
        question = models.CharField(max_length=200)
        objects = PollManager()

    class Response(models.Model):
        poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
        # ...

通过这个示例，你可以使用 `OpinionPoll.objects.with_counts()` 来获取带有额外的 `num_responses` 属性附加的 `OpinionPoll` 对象的 `QuerySet`。

自定义 `Manager` 方法能返回任何东西，没有强制它必须返回一个 `QuerySet`。

另一个需要注意的是，`Manager` 方法可以访问 `self.model` 来获取它们附加的模型类。

### 修改管理器的初始 `QuerySet`

`Manager` 的基础 `QuerySet` 会返回系统中所有的对象。例如，使用以下模型:

    from django.db import models

    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

……语句 `Book.objects.all()` 会返回数据库中所有的书。

你可以通过重写 `Manager.get_queryset()` 方法来覆盖 `Manager` 的基础 `QuerySet`。 `get_queryset()` 返回的 `QuerySet` 应该包含你需要的属性。

例如，以下模型有 两个 `Manager` —— 一个返回所有对象，另一个仅返回 Roald Dahl 写的书:

    # First, define the Manager subclass.
    class DahlBookManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(author="Roald Dahl")

    # Then hook it into the Book model explicitly.
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

        objects = models.Manager()  # The default manager.
        dahl_objects = DahlBookManager()  # The Dahl-specific manager.

使用这个实例模型时， `Book.objects.all()` 会返回数据库中所有的书，而 `Book.dahl_objects.all()` 仅返回 Roald Dahl 写的书。

因为 `get_queryset()` 返回一个 `QuerySet` 对象，你可以在上面调用 `filter()`， `exclude()` 和其它的 `QuerySet` 方法。所以，以下语句是等效的:

    Book.dahl_objects.all()
    Book.dahl_objects.filter(title="Matilda")
    Book.dahl_objects.count()

本例同时介绍了另一个有趣的技巧：在一个模型中使用多个管理器。你可以为一个模型添加任意多个 `Manager()`。为模型定义通用 "filters" 的非重复方式。

例如：

    class AuthorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="A")

    class EditorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="E")

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = models.Manager()
        authors = AuthorManager()
        editors = EditorManager()

本例允许你调用 `Person.authors.all()`， `Person.editors.all()` 和 `Person.people.all()`，返回符合期望的结果。

### 默认管理器

Model._default_manager

若你使用自定义 `Manager` 对象，注意 Django 遇到的第一个 `Manager` （按照你在模型中定义的顺序）会拥有一个独特的状态。Django 将类定义中的第一个 `Manager` 视作 “默认” `Manager`，Django 的几个组件（包括 `dumpdata`）在用到该模型时会独立地调用该 `Manager`。故此，选择默认管理器时要万分小心，避免遇到重写的 `get_queryset()` 无法获取期望的结果这种情况。

你可以通过 `Meta.default_manager_name` 指定一个自定义的默认管理器。

若你正在编写的代码必须处理未知模型，例如，在实现了通用视图的第三方应用中使用这个管理器（或 `_base_manager`），而不是假定该模型有一个名为 `objects` 的管理器。

### 基础管理器

Model._base_manager

#### 用于访问关联对象的管理器

By default, Django uses an instance of the `Model._base_manager` manager class when accessing related objects (e.g. `choice.question`), not the `_default_manager` on the related object. This is because Django needs to be able to retrieve the related object, even if it would otherwise be filtered out (and hence be inaccessible) by the default manager.

若基本管理器类 (`django.db.models.Manager`) 无法满足需求，你可以通过设置 `Meta.base_manager_name` 告诉 Django 使用哪个类。

在关联模型上执行查询时不会使用基础管理器，或者当访问一对多或多对多关系( accessing a one-to-many or many-to-many relationship )。例如，若 来自教程 的模型 `Question` 有个 `deleted` 字段，还有一个基础管理器，用于过滤掉 `deleted=True` 的实例。由 `Choice.objects.filter(question__name__startswith='What')` 返回的查询结果集会包含关联至已删除的问题的选项。

#### 不要在这类管理器子类中过滤掉任何结果

该管理器用于访问由其它模型关联过来的对象。这些情况下，Django 要能访问待获取模型的全部对象，这样就能检索出其指向的 任何东西。

因此，你不应该覆盖 `get_queryset()` 来过滤任何rows。如果你这么做，Django 会返回不完整的结果。

### 管理器调用自定义 `QuerySet` 方法

因为大部分的标准 `QuerySet` 方法能直接从 `Manager` 访问，这个实例仅适用于你在自定义 `QuerySet` 中定义了额外方法，且在 `Manager` 中实现了它们:

    class PersonQuerySet(models.QuerySet):
        def authors(self):
            return self.filter(role="A")

        def editors(self):
            return self.filter(role="E")

    class PersonManager(models.Manager):
        def get_queryset(self):
            return PersonQuerySet(self.model, using=self._db)

        def authors(self):
            return self.get_queryset().authors()

        def editors(self):
            return self.get_queryset().editors()

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = PersonManager()

本例允许你从管理器 `Person.people` 直接调用 `authors()` 和 `editors()`。

### 创建带有 `QuerySet` 方法的管理器

要替换前面的要求复制 `QuerySet` 和 `Manager` 方法的方案， 可以用 `QuerySet.as_manager()` 创建一个 `Manager` 实例，拷贝了自定义 `QuerySet` 的方法:

    class Person(models.Model):
        ...
        people = PersonQuerySet.as_manager()

由 `QuerySet.as_manager()` 创建的 `Manager` 实例实质上等价于前面例子中的 `PersonManager`。

不是每个 `QuerySet` 方法在 `Manager` 层都是有意义的；例如，我们故意阻止 `QuerySet.delete()` 被拷贝进 `Manager` 类中。

方法拷贝规则如下：

- 公开方法默认会被拷贝。

- 私有方法（以下划线打头）默认不会被复制。

- `queryset_only` 属性值为 `False` 的方法总是会被复制。

- `queryset_only` 属性值为 `True` 的方法永远不会被复制。

例如：

    class CustomQuerySet(models.QuerySet):
        # Available on both Manager and QuerySet.
        def public_method(self):
            return

        # Available only on QuerySet.
        def _private_method(self):
            return

        # Available only on QuerySet.
        def opted_out_public_method(self):
            return

        opted_out_public_method.queryset_only = True

        # Available on both Manager and QuerySet.
        def _opted_in_private_method(self):
            return

        _opted_in_private_method.queryset_only = False

#### `from_queryset()`

classmethod from_queryset(queryset_class)

对于进阶用法，你可能同时要一个自定义 `Manager` 和一个自定义 `QuerySet`。你可以通过调用 `Manager.from_queryset()` 达成目的，这将会返回一个自定义基础 `Manager` 的子类，带有一份自定义 `QuerySet` 方法的拷贝:

    class CustomManager(models.Manager):
        def manager_only_method(self):
            return

    class CustomQuerySet(models.QuerySet):
        def manager_and_queryset_method(self):
            return

    class MyModel(models.Model):
        objects = CustomManager.from_queryset(CustomQuerySet)()

还可以将生成的类存储到变量中：

    MyManager = CustomManager.from_queryset(CustomQuerySet)

    class MyModel(models.Model):
        objects = MyManager()

### 自定义管理器和模型继承

下面是 Django 如何处理自定义管理器和 模型继承：

1. 基类的管理器总是被子类以 Python 的普通名称解析顺序继承（子类上的属性会覆盖所有父类上的同名属性；直接父类会覆盖更上一级的，以此类推）。

2. 如果没有在模型或其父类申明管理器，Django 会自动创建 `objects` 管理器。

3. 一个类的默认管理器要么由 `Meta.default_manager_name` 指定，要么是模型中申明的第一个管理器，或者是直接父模型的默认管理器。

如果您想通过抽象基类在一组模型上安装自定义管理器，但仍能自定义默认管理器，这些规则提供了必要的灵活性。例如，假设有此基类:

    class AbstractBase(models.Model):
        # ...
        objects = CustomManager()

        class Meta:
            abstract = True

如果你在子类中直接使用这个，如果你在子类中没有声明任何管理器，那么 `objects` 将是默认的管理器：

    class ChildA(AbstractBase):
        # ...
        # This class has CustomManager as the default manager.
        pass

如果您想继承 `AbstractBase`，但提供不同的默认管理器，则可以在子类上提供该默认管理器:

    class ChildB(AbstractBase):
        # ...
        # An explicit default manager.
        default_manager = OtherManager()

这里的 `default_manager` 是默认的。 `objects` 管理器仍然可用，因为它是继承的，但没有被当做默认管理器。

最后，对于这个示例，假设您想要向子类中添加额外的管理器，但是仍然使用来自 `AbstractBase` 的默认管理器。您不能直接在子类中添加新的管理器，因为这将覆盖默认管理器，并且您还必须显式地申明来自抽象基类的所有管理器。解决方案是将这个管理器放到另一个基类中，并在默认管理器 之后 将其引入继承层次结构:

    class ExtraManager(models.Model):
        extra_manager = OtherManager()

        class Meta:
            abstract = True

    class ChildC(AbstractBase, ExtraManager):
        # ...
        # Default manager is CustomManager, but OtherManager is
        # also available via the "extra_manager" attribute.
        pass

请注意，虽然可以在抽象模型上 定义 自定义管理器，但不能使用抽象模型 调用 任何方法。即:

    ClassA.objects.do_something()

是合法的，但:

    AbstractBase.objects.do_something()

会引发一个异常。这是因为管理器意在封装管理映射对象集合的逻辑。因为您不能拥有抽象对象的集合，所以管理抽象对象是没有意义的。如果您有适用于抽象模型的功能，则应该将该功能放在抽象模型的 `静态方法` 或 `类方法` 中。

### 执行关系

无论你向自定义的 `Manager` 添加了什么特性，都必须能够对 `Manager` 实例进行浅拷贝；也就是说，以下代码必须可以正常工作：

    >>> import copy
    >>> manager = MyManager()
    >>> my_copy = copy.copy(manager)

Django 在某些查询期间对管理器对象进行浅拷贝；如果您的管理器无法被复制，那么这些查询将失败。

对于大多数的资源管理器来说，这不是问题。若你只是为 `Manager` 添加简单的方法，一般不会疏忽地把 `Manager` 变的不可拷贝。但是，若重写了 `Manager` 对象用于控制对象状态的 `__getattr__` 或其它私有方法，你需要确认你的修改不会影响 `Manager` 被复制。