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
被复制。
7月 22, 2024