25

我已经阅读了官方 Django文档中的定义,但我仍然对 a 的Manager作用感到困惑。

文档说它们允许您对数据库表/模型进行操作,但我仍然不明白这一点。

有人可以向我解释经理及其角色吗?最好有一个例子的答案。

4

3 回答 3

28

管理器通常是隐藏在 django 程序员之外的东西,django 使用它来连接model代码和数据库后端。

当您查询 django ORM 时,您可以通过调用

from my_app.models import MyModel

mms = MyModel.objects.all()

在这种情况下,objects函数的一部分是管理器返回的。如果您希望 MyModel 只获取blue MyModel实例(数据库也可能包含red模型),那么您可以创建一个管理器并破解您的模型

class BlueManager(models.Manager):
    def get_query_set(self):
        return super(BlueManager, self).get_query_set().filter(colour='Blue')

class MyModel(models.Model):
     colour = models.CharField(max_length=64)
     blue_objects = BlueManager()

并打电话

MyModel.blue_objects.all()

只会返回带有colouras 的对象blue。请注意,这是过滤模型的一种非常糟糕的方法!

Manager如果他们要修改QuerySet管理器通常会返回的 s 或者如果您需要添加“表”级别的查询(而不是常规的 django “行”级别),通常需要修改接口。管理器的文档非常完整,包含几个示例。

于 2013-02-04T14:57:43.247 回答
10

管理器是应用程序和数据库之间的某种“门”。一件好事是您可以为模型定义自己的基本查询集。例如:如果您有带有“可用性”字段的模型“书”,您可以准备自己的查询集,它过滤特定类型的可用性类型:

模型.py:

class AvailableBookManager(models.Manager):
    def get_query_set(self):
        return super(AvailableBookManager, self).get_query_set().filter(availability=1)

class Book(models.Model):
   (...)#fields definition
 
   objects = models.Manager() #default manager
   available_objects = AvailableBookManager() #own manager

现在你可以像这样使用:

books = Book.available_objects.all()

而不是使用:

books = Book.objects.filter(available=1)
于 2013-02-04T15:02:27.790 回答
8

定义

从文档:

Manager 是一个 Django 类,它提供数据库查询操作和 Django 模型之间的接口。

换句话说,在 Django 模型中,管理器是与数据库交互的接口。例如,当您想从数据库中检索对象时,您需要在模型类上QuerySet通过 a构造一个。Manager

默认情况下,可以通过该Model.objects属性使用管理器。这位经理是django.db.models.Manager。但是,扩展它并更改默认管理器非常简单。

自定义管理器

文档

您可以通过扩展基础 Manager 类并在模型中实例化您的自定义 Manager 来在特定模型中使用自定义 Manager。

您可能想要自定义 Manager 的原因有两个(它们都不是独占的):

  1. 添加额外的 Manager 方法
  2. 修改 Manager 返回的初始 QuerySet

示例:向 Manager 添加额外的方法

from django.db import models

class DocumentManager(models.Manager):
    def pdfs(self):
        return self.filter(file_type='pdf')

    def smaller_than(self, size):
        return self.filter(size__lt=size)


class Document(models.Model):
    name = models.CharField(max_length=30)
    size = models.PositiveIntegerField(default=0)
    file_type = models.CharField(max_length=10, blank=True)

    objects = DocumentManager()

    def __str__(self) -> str:
        return self.name

示例:修改 Manager 返回的初始 QuerySet

from django.db import models


class AuthorManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(first_name__startswith='M')

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.EmailField()

    objects = AuthorManager()

    def __str__(self) -> str:
        return f"{self.first_name} {self.last_name}"

示例:同时有多个经理

同一模型可以有多个管理器。

from django.db import models
from django.db.models.functions import Length

class BookTitleManager(models.Manager):
    def short_titles(self):
        return self.annotate(length=Length('title')).filter(length__lte=20)

    def long_titles(self):
        return self.annotate(length=Length('title')).filter(length__gt=20, length__lte=30)
    
    def very_long_titles(self):
        return self.annotate(length=Length('title')).filter(length__gt=30)

    def starts_with(self, letter):
        return self.filter(title__startswith=letter)


class BookPagesManager(models.Manager):
    def small_books(self):
        return self.filter(pages__lt=200)
    
    def medium_books(self):
        return self.filter(pages__gte=200, pages__lt=300)
    
    def large_books(self):
        return self.filter(pages__gte=300, pages__lte=500)


class Book(models.Model):
    title = models.CharField(max_length=255)
    author = models.CharField(max_length=255)
    pages = models.IntegerField()

    objects = models.Manager()
    titles = BookTitleManager()
    sizes = BookPagesManager()

    def __str__(self) -> str:
        return f'{self.title} by {self.author}'

在前面的代码示例中,有 3 个管理器:分别为default和models.Manager分配给BookTitleManager和。BookPagesManagerobjectstitlessizes

以前的管理器的问题是您不能将它们链接如下:

>>> Book.titles.long_titles().starts_with('P')
AttributeError: 'QuerySet' object has no attribute 'starts_with'

示例:自定义管理器和查询集(允许使用链)

如果要链接管理器中定义的方法,则应定义一个自定义 QuerySet,如下所示:

from django.db import models
from django.db.models.functions import Length


class AuthorQuerySet(models.QuerySet):
    def long_first_name(self):
        return self.annotate(length=Length("first_name")).filter(length__gte=10)

    def short_last_name(self):
        return self.annotate(length=Length("last_name")).filter(length__lte=10)


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

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

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


class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.EmailField()

    objects = AuthorManager()

    def __str__(self) -> str:
        return f"{self.first_name} {self.last_name}"

示例:用作管理器的自定义查询集

在管理器中仅定义自定义QuerySets时,可以简单地扩展并将其QuerySet设置为管理器。

from django.db import models
from django.db.models.functions import Length


class PublisherQuerySet(models.QuerySet):
    def long_name(self):
        return self.annotate(length=Length("name")).filter(length__gte=15)

    def long_address(self):
        return self.annotate(length=Length("address")).filter(length__gte=25)

    def country_starts_with(self, letter):
        return self.filter(country__startswith=letter)


class Publisher(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=255)
    country = models.CharField(max_length=100)

    objects = PublisherQuerySet.as_manager() # uses QuerySet as Manager

    def __str__(self) -> str:
        return self.name

也要记住

  • 如果要objects用作字段名称,或者要使用 Manager 以外的名称objects,则可以按模型重命名。要重命名给定类的管理器,请在该模型上定义类型为 models.Manager() 的类属性。
class Document(models.Model):
    name = models.CharField(max_length=30)
    size = models.PositiveIntegerField(default=0)
    file_type = models.CharField(max_length=10, blank=True)

    stuff = models.Manager()

    def __str__(self) -> str:
        return self.name

在前面的代码示例中,调用Document.objects将生成AttributeError异常,因为默认管理器已被重命名,现在可以使用的是Document.stuff.

  • 管理器只能通过模型​​类而不是模型实例来访问,以强制区分“表级”操作和“记录级”操作。

  • 如果模型具有 ForeignKey,则外键模型的实例将有权访问返回第一个模型的所有实例的 Manager。默认情况下,此 Manager 名为FOO_set,其中FOO源模型名称为小写。

于 2020-07-26T03:07:45.737 回答