使用这种继承方式时,每一个层级下的每个 model 都是一个真正意义上完整的 model 。 每个 model 都有专属的数据表,都可以查询和创建数据表。 继承关系在子 model 和它的每个父类之间都添加一个链接 (通过一个自动创建的隐含的 OneToOneField 来实现)。
例如:
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
# 继承自Place
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
Restaurant 现在除了拥有 serves_hot_dogs、serves_pizza,两个字段外,还拥有继承得来的 name 、address 两字段。所以下面两个语句都是可以运行的:
Place.objects.filter(name="辉记糖水")
Restaurant.objects.filter(name="辉记糖水")
如果有一个 Place ,它同时也是一个 Restaurant, 那么你可以使用 model 的小写形式从 Place 对象中获得与其对应的 Restaurant对象:
>>> p = Place.objects.get(name="辉记糖水")
>>> p.restaurant
<Restaurant: 辉记糖水>
但是,如果上例中的 p 并不是 Restaurant (比如它仅仅只是 Place 对象,或者它是其他类的父类),那么在引用 p.restaurant 就会抛出Restaurant.DoesNotExist 异常。
继承与反向关联
因为多表继承使用了一个隐含的 OneToOneField 来链接子类与父类,但是这个 OnetoOneField 字段默认的 related_name 值与 ForeignKey 和 ManyToManyField 默认的反向名称相同。
当一个子类含有多对一或是多对多关系,你就必须在每个多对一和多对多字段上强制指定 related_name。如果你没这么做,Django 就会在你运行验证(validation) 时抛出异常。
例如,仍以上面 Place类为例,我们创建一个带有 ManyToManyField字段的子类:
class Supplier(Place):
customers = models.ManyToManyField(Place)
这会产生一个错误:
Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.
HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.
要解决这个问题,要向 customers 字段中添加 related_name :
class Supplier(Place):
customers = models.ManyToManyField(Place, related_name='provider')
要查询 Supplier 时就可以用 provider 来调用:
>>> p = Place.objects.get(name='辉记糖水')
# 查找辉记糖水的供应商
>>> p.provider.all()
<QuerySet [<Supplier: 糖厂>]>