模型继承之多表继承2之代理继承
2018-08-24 本文已影响12人
陆_志东
在多表继承文章中,已经讲过,多表继承都是完整的model,都会创建数据库表,
那么可以不可以像抽象基类那样不让继承的子类创建数据表呢?方法就是代理继承
代理继承要做的就是:为原始模型创建一个代理 。你可以创建,删除,更新代理 model 的实例,而且所有的数据都可以像使用原始 model 一样被保存。 不同之处在于:你可以在代理 model 中改变默认的排序设置和默认的 manager ,更不会对原始 model 产生影响。
所以代理继承只是更改model在Python层的行为表现,比如:更改默认的 manager ,或是添加一个新方法。
使用了代理继承之后,原model和子model共用同一张数据表
例:假设你想给 Person 模型添加一个方法。你可以这样做:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
特别的是,Person 的任何实例也可以通过 MyPerson访问,反之亦然:
>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>
你也可以使用代理 model 给 model 定义不同的默认排序设置。 你可能并不想每次都给Person模型排序,但是使用代理的时候总是按照last_name属性排序。这非常容易:
class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True
注意事项:
- 查询集始终返回请求的模型
也就是说,没有办法让django在查询Person对象时返回MyPerson对象。Person 对象的查询集会返回相同类型的对象。 - 代理模型必须继承自一个非抽象基类。
你不能继承自多个非抽象基类,这是因为一个代理 model 不能连接不同的数据表。 代理 model 也可以继承任意多个抽象基类,但前提是它们没有 定义任何 model 字段。因为代理模型不更改原模型字段,只是添加额外的方法,所以你继承的抽象基类只能有方法,不能有模型字段
代理模型的管理器
如果你没有在代理 模型中定义任何管理器 ,代理模型就会从父类中继承管理器 。 如果你在代理模型中定义了一个管理器 ,它就会变成默认的管理器 ,不过定义在父类中的管理器仍然有效。
继续上面的例子,当你查询Person模型的时候,你可以改变默认 管理器,例如:
from django.db import models
class NewManager(models.Manager):
# ...
pass
class MyPerson(Person):
objects = NewManager() # 替换现有的管理器
class Meta:
proxy = True
如果你想要向代理中添加新的管理器,而不是替换现有的默认管理器,你可以创建一个含有新的管理器的基类,并继承时把他放在主基类的后面
# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
secondary = NewManager()
class Meta:
abstract = True
class MyPerson(Person, ExtraManagers): # 这样就会有两个管理器 objects 和 secondary
class Meta:
proxy = True
多重继承
参考网址
尽量不要多重继承,因为Python的多重继承很容易出现问题,你应该尝试将你的继承关系保持得尽可能简洁和直接,这样你就不必费很大力气来弄清楚某段特定的信息来自哪里。
django不允许重写字段
如果基类中有一个 author字段,你就不能在子类中创建任何名为 author的字段。