A Manager 是向django模型提供数据库查询操作的接口。至少一个 Manager 存在于Django应用程序中的每个模型。
路 Manager 课程工作记录在 进行查询 ;此文档专门涉及自定义的模型选项 Manager 行为。
默认情况下,Django添加了 Manager 用名字 objects 给每一个Django模型班。但是,如果您想使用 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 方法和/或修改初始值 QuerySet 这个 Manager 返回。
追加 Manager 方法是向模型添加“表级”功能的首选方法。(对于“行级”功能——即作用于模型对象的单个实例的函数——使用 Model methods 不是习惯 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() 想要拿到一个 QuerySet 的 OpinionPoll 带有额外内容的物体 num_responses 附加属性。
风俗习惯 Manager 方法可以返回所需的任何内容。它不必返回 QuerySet .
另一件需要注意的是, Manager 方法可以访问 self.model 以获取它们所属的模型类。
QuerySet¶A 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 碱 QuerySet 通过覆盖 Manager.get_queryset() 方法。 get_queryset() 应该归还 QuerySet 使用您需要的属性。
例如,以下模型具有 two Manager S——一个返回所有对象,一个只返回罗尔德·达尔的书:
# 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() 将只返回罗尔德·达尔写的那些。
因为 get_queryset() 返回一个 QuerySet 对象,您可以使用 filter() , exclude() 和所有其他 QuerySet 方法。所以这些声明都是合法的::
Book.dahl_objects.all()
Book.dahl_objects.filter(title="Matilda")
Book.dahl_objects.count()
这个例子还指出了另一个有趣的技术:在同一个模型上使用多个管理器。您可以附加尽可能多的 Manager() 根据您想要的方式将实例添加到模型中。这是一种为模型定义常用“过滤器”的非重复方法。
例如::
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() 产生可预测的结果。
如果使用自定义 Manager 对象,注意第一个 Manager Django遇到(按照模型中定义的顺序)具有特殊的状态。Django解释第一个 Manager 在类中定义为“默认” Manager 以及Django的几个部分(包括 dumpdata )将使用 Manager 专为那个型号设计。因此,在选择默认管理器时要小心,以避免覆盖 get_queryset() 导致无法检索要使用的对象。
可以使用指定自定义默认管理器 Meta.default_manager_name .
如果您正在编写一些必须处理未知模型的代码,例如,在实现通用视图的第三方应用程序中,请使用此管理器(或 _base_manager )而不是假设模型 objects 经理。
此管理器用于访问与其他模型相关的对象。在这种情况下,Django必须能够看到它正在获取的模型的所有对象,以便 任何东西 可以检索到。
因此,您不应该重写 get_queryset() 以过滤掉任何行。如果您这样做,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()
此示例允许您调用 authors() 和 editors() 直接从经理那里 Person.people .
QuerySet 方法¶代替上述方法,该方法要求在 QuerySet 以及 Manager , QuerySet.as_manager() 可用于创建 Manager 有一个自定义的副本 QuerySet 方法:
class Person(models.Model):
...
people = PersonQuerySet.as_manager()
这个 Manager 实例创建者 QuerySet.as_manager() 将几乎等同于 PersonManager 来自上一个示例。
不是每一个 QuerySet 方法在 Manager 级别;例如,我们故意阻止 QuerySet.delete() 方法从复制到 Manager 类。
方法按照以下规则复制:
默认情况下复制公共方法。
默认情况下,不会复制私有方法(以下划线开头)。
方法与A queryset_only 属性设置为 False 总是被复制。
方法与A 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()¶对于高级用法,您可能需要 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如何处理自定义管理器和 model inheritance :
使用Python的常规名称解析顺序(子类上的名称覆盖所有其他名称,然后在第一个父类上出现名称,依此类推),基类中的管理器始终由子类继承。
如果模型和/或其父代上没有声明管理器,Django将自动创建 objects 经理。
类上的默认管理器可以是 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 manager仍然可用,因为它是继承的,但不用作默认值。
最后,对于这个示例,假设您希望向子类添加额外的管理器,但仍然使用默认的From 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()
将引发异常。这是因为管理器旨在封装用于管理对象集合的逻辑。因为您不能拥有抽象对象的集合,所以管理它们是没有意义的。如果您有应用于抽象模型的功能,那么应该将该功能放在 staticmethod 或 classmethod 抽象模型。
无论您为您的客户添加了什么功能 Manager ,必须有可能制作一个浅层副本 Manager 实例;即,以下代码必须正常工作:
>>> import copy
>>> manager = MyManager()
>>> my_copy = copy.copy(manager)
Django在某些查询期间对管理器对象进行浅复制;如果无法复制管理器,则这些查询将失败。
对于大多数自定义管理器来说,这不是一个问题。如果你只是在你的 Manager ,您不太可能无意中创建 Manager 不可复制的但是,如果你要超越 __getattr__ 或者你的私人方法 Manager 控制对象状态的对象,应确保不影响 Manager 被复制。
5月 28, 2025