管理器(Manager)

管理器是 Django 的模型進行數(shù)據(jù)庫查詢操作的接口。Django 應用的每個模型都擁有至少一個管理器。




管理器的名字

假設有以下 model:

from django.db import models

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

    def __str__(self):
        return self.title

默認情況下,Django 為每個模型類添加一個名為 objects 的管理器。你可以在每個模型類中重命名它們:

class Book(models.Model):
    #...
    book_manager = models.Manager()

現(xiàn)在就可以用 book_manager 來調用 Book 模型的管理器了,例如:

b = Book.book_manager.get(title='圖書1')




自定義管理器

你可以在模型中使用自定義的管理器,方法是繼承 Manager 基類并實例化你的自定義管理器。

自定義管理器一般有兩個用途:向管理器類中添加額外的方法,或者修改管理器返回的原始查詢集。




1.添加額外的管理器方法

添加額外管理器方法是為你的類增加“表級”功能的首選方式。 (如果要添加行級功能 —— 比如只對某個模型的實例起作用 ——應使用模型方法 ,而不是管理器方法。)

一個最簡單例子:

from django.db import models

# 自定義管理器
class BookManager(models.Manager):
    def test(self):
        return '一個測試'

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

    objects = BookManager()

    def __str__(self):
        return self.title

shell 中測試下:

>>> from myApp.models import Book
>>> Book.objects.test()

'一個測試'

我們來寫一個更有意義的例子,添加一個管理器方法,直接執(zhí)行 SQL 語句,查詢某個作者所寫的圖書的總數(shù):

from django.db import models
from django.db import connection 

# 自定義管理器
class BookManager(models.Manager):
    # 自定義管理方法
    def author_counts(self, author):
        cursor = connection.cursor()

        # 直接執(zhí)行 SQL 語句
        ins = ("""
            SELECT COUNT(*)
            FROM myApp_book
            WHERE author='{}';
            """).format(author)
        counts = cursor.execute(ins)

        for i in counts:
            count = i[0]

        return count

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

    objects = BookManager() # 指定使用哪個管理器

    def __str__(self):
        return self.title

shell 中測試下:

>>> from myApp.models import Book

>>> Book.objects.author_counts(author='作者1')
2

>>> Book.objects.author_counts(author='作者2')
1




2.修改管理器的原始查詢集

你可以通過超類覆蓋 Manager.get_queryset() 方法來覆蓋管理器自帶的 Queryset。自定義 get_queryset() 方法能根據(jù)你所需要的屬性返回查詢集。

例如,下面的模型有兩個管理器,一個返回所有的對象,另一個則只返回作者是 “作者1” 的對象:

from django.db import models
from django.db import connection 

# 自定義管理器
class BookManager(models.Manager):

    def get_queryset(self):
        return super(BookManager, self).get_queryset().filter(author='作者1')

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

    objects = models.Manager() # 默認管理器
    book_manager = BookManager() # 自定義管理器

    def __str__(self):
        return self.title

shell 中測試下:

from myApp.models import Book

# 使用自定義的管理器 book_manager,只會返回 author 是 “作者1” 的對象
>>> Book.book_manager.all()
<QuerySet [<Book: 圖書1>, <Book: 圖書2>]>

# 使用默認管理器,返回全部對象
>>> Book.objects.all()
<QuerySet [<Book: 圖書1>, <Book: 圖書2>, <Book: 圖書3>, <Book: 圖書4>]>

同一模型使用多個管理器,在一個模型里面添加多個 Manager 實例。這是給模型添加通用過濾器(選擇器)的一個簡單方法:

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

class EditorManager(models.Manager):
    def get_queryset(self):
        return super(EditorManager, self).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() # 只選擇 role=A 的對象
    editors = EditorManager() # 只選擇 role=E 的對象




3.從 Manager 中調用自定義的 QuerySet

雖然大多數(shù)標準查詢集的方法可以從管理器中直接訪問到,但是如果你需要將一些被定義到一個自定義查詢集中的額外方法也在管理器上實現(xiàn),下面所展示的這個例子是唯一可行辦法:

from django.db import models

# 自定義的 QuerySet,并新增了 QuerySet 的方法
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()

    def __str__(self):
        return self.first_name + self.last_name

現(xiàn)在可以用 Person.people.authors() 的形式來調用了。

shell 中測試下:

from myApp.models import Person

# 選擇 role=A 的對象
>>> Person.people.authors() 
<QuerySet [<Person: 李小明>, <Person: 張小花>]>

# 選擇 role=E 的對象
>>> Person.people.editors()
<QuerySet [<Person: 王小紅>, <Person: 林小白>]>




4.使用 QuerySet 的方法作為 Manager

上面的方法要求同一個方法在查詢集和管理器上都創(chuàng)建,QuerySet.as_manager() 可以用來創(chuàng)建一個帶有自定義查詢集方法副本的管理器實例:

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

通過 QuerySet.as_manager() 創(chuàng)建的管理器 實例,實際上等價于上面例子中的 PersonManager。

看一個完整例子:

from django.db import models

# 自定義的 QuerySet,并新增了 QuerySet 的方法
class PersonQuerySet(models.QuerySet):
    def authors(self):
        return self.filter(role='A')

    def editors(self):
        return self.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'))
        )

    # 把 PersonQuerySet 作為管理器
    people = PersonQuerySet.as_manager()

    def __str__(self):
        return self.first_name + self.last_name

照樣,我們可以用 Person.people.editors() 的形式來調用。

from myApp.models import Person

# 選擇 role=A 的對象
>>> Person.people.authors() 
<QuerySet [<Person: 李小明>, <Person: 張小花>]>

并不是每個查詢集的方法都在管理器層面上有意義。比如 QuerySet.delete(),我們有意防止它復制到管理器 中。

方法按照以下規(guī)則進行復制:

  • 公共方法默認被復制。
  • 私有方法(前面帶一個下劃線)默認不被復制。
  • 帶 queryset_only 屬性,并且值為False的方法總是被復制。
  • 帶 queryset_only 屬性,并且值為True 的方法不會被復制。

例子:

class PersonQuerySet(models.QuerySet):
    ......

    # 可在 manager 中調用
    def public_method(self):
        return '公共方法'

    # 不可在 manager 中調用
    def _private_method(self):
        return '私有方法'

    # 不可在 manager 中調用
    def opted_out_public_method(self):
        return '私有方法'
    opted_out_public_method.queryset_only = True

    # 可在 manager 中調用
    def _opted_in_private_method(self):
        return '公共方法'
    _opted_in_private_method.queryset_only = False




from_queryset

在進一步的使用中,你可能想創(chuàng)建一個自定義管理器和一個自定義查詢集。

你可以調用 Manager.from_queryset(),它會返回管理器的一個子類,帶有自定義查詢集所有方法的副本:

from django.db import models

class BaseManager(models.Manager):
    def manager_only_method(self):
        return '管理器獨有方法'

class PersonQuerySet(models.QuerySet):
    def manager_and_queryset_method(self):
        return '管理器和查詢集共有方法'


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'))
        )

    objects = BaseManager.from_queryset(PersonQuerySet)()

    def __str__(self):
        return self.first_name + self.last_name

shell 中測試下:

>>> Person.objects.manager_only_method()
'管理器獨有方法'

>>> Person.objects.manager_and_queryset_method()
'管理器和查詢集共有方法'

>>> Person.objects.all().manager_and_queryset_method()
'管理器和查詢集共有方法'
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 原文:https://my.oschina.net/liuyuantao/blog/751438 查詢集API 參...
    陽光小鎮(zhèn)少爺閱讀 3,958評論 0 8
  • Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606網(wǎng)站:h...
    布客飛龍閱讀 652評論 0 35
  • Django 1.8.2 文檔Home | Table of contents | Index | Modules...
    軒轅小愛閱讀 2,425評論 0 2
  • 安寧的手機上顯示著一條微信:“班長。” 是高中同學肖兌。 從見到安寧那一刻她就一直這樣叫安寧。 肖兌的的特點是男朋...
    威德閱讀 370評論 1 0

友情鏈接更多精彩內(nèi)容