管理器是 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()
'管理器和查詢集共有方法'