类继承和模型管理器两者之间配合得并不是很好。 管理器一般只对其定义所在的类起作用,在子类中对其继承绝对不是一个好主意。 而且,因为第一个管理器为默认的管理器,所以对默认的管理器 进行控制是非常必要的。
下面是 Django 如何处理自定义管理器和模型继承:
1. 定义在非抽象基类中的管理器是不会被子类继承的。如果你想从一个非抽象基类中重用管理器,只能在子类中重定义管理器。这是因为这种管理器与定义它的模型 绑定得非常紧密,所以继承它们经常会导致异常的结果(特别是默认管理器运行的时候)。 因此,它们不应继承给子类。
2. 定义在抽象基类中的管理器总是被子类继承的,是按 Python 的命名解析顺序解析的(首先是子类中的命名覆盖所有的,然后是第一个父类的,以此类推)。 抽象类用来提取子类中的公共信息和行为,定义公共管理器也是公共信息的一部分。
3. 如果类当中显示定义了默认管理器,Django 就会以此做为默认管理器;否则就会从第一个抽象基类中继承默认管理器; 如果没有显式声明默认管理器,那么 Django 就会自动添加默认管理器。
如果你想在一组模型上安装一系列自定义管理器,上面提到的这些规则就已经为你的实现提供了必要的灵活性。你可以继承一个抽象基类,但仍要自定义默认的管理器。
from django.db import models
# 一个自定义管理器
class CustomManager(models.Manager):
def test(self):
return '一个测试'
# 一个抽象基类
class BasePerson(models.Model):
name = models.CharField(max_length=200)
objects = CustomManager()
class Meta:
abstract = True
# 继承自抽象基类
class Student(BasePerson):
school = models.CharField(max_length=200)
def __str__(self):
return self.name
上面例子中你在子类中没有定义管理器,默认管理器就是从基类中继承的 objects:
>>> from myApp.models import Student
>>> Student.objects.all()
<QuerySet [<Student: 小明>]>
# 自定义的管理器方法也是能够使用的
>>> Student.objects.test()
'一个测试'
如果你继承 AbstractBase 的管理器,却又想提供另一个默认管理器,那么你可以在子类中定义默认管理器:
from django.db import models
# 一个自定义管理器
class CustomManager(models.Manager):
def test(self):
return '一个测试'
# 一个抽象基类
class BasePerson(models.Model):
name = models.CharField(max_length=200)
objects = CustomManager()
class Meta:
abstract = True
# 一个新的自定义管理器
class NewManager(models.Manager):
def new_test(self):
return '一个新的测试'
# 继承自抽象基类
class Student(BasePerson):
school = models.CharField(max_length=200)
# 设置新的默认管理器
# 管理器名字可以自定义
default_manager = NewManager()
def __str__(self):
return self.name
现在 Student 子类的默认管理器是 default_manager 了:
>>> from myApp.models import Student
>>> Student.default_manager.all()
<QuerySet [<Student: 小明>]>
>>> Student.default_manager.new_test()
'一个新的测试'
# 继承自 AbstractBase 的管理器仍能使用
>>> Student.objects.test()
'一个测试'
最后再举个例子,假设你想在子类中再添加一个额外的管理器,但是很想使用从 AbstractBase 继承的管理器做为默认管理器。那么,你不能直接在子类中添加新的管理器,否则就会覆盖掉默认管理器,而且你必须对派生自这个基类的所有子类都显示指定管理器。
解决办法就是在另一个基类中添加新的管理器,然后继承时将其放在默认管理器所在的基类 之后。例如:
from django.db import models
# 一个自定义管理器
class CustomManager(models.Manager):
def test(self):
return '一个测试'
# 一个抽象基类
class BasePerson(models.Model):
name = models.CharField(max_length=200)
objects = CustomManager()
class Meta:
abstract = True
# 一个新的自定义管理器
class NewManager(models.Manager):
def new_test(self):
return '一个新的测试'
# 抽象基类,包含新的自定义管理器
class ExtraManager(models.Model):
extra_manager = NewManager()
class Meta:
abstract = True
# 继承了两个抽象基类,前者的管理器作为默认管理器
class Student(BasePerson, ExtraManager):
school = models.CharField(max_length=200)
def __str__(self):
return self.name
现在,子类 Student 的默认管理器为从 AbstractBase 继承的 objects,同时还拥有另一个管理器 extra_manager 。
>>> Student.objects.test()
'一个测试'
>>> Student.extra_manager.new_test()
'一个新的测试'