Model inheritance 模型繼承

Django中模型的繼承與Python普通類的繼承一樣,不過(guò)基類要是django.db.models.Model
在Django中有三種繼承的方式

  • 僅僅想用父類保存一下不是每個(gè)子類都鍵入的信息,抽象class是很好的選擇
  • 繼承一個(gè)存在model,并且想讓每個(gè)model都有一個(gè)數(shù)據(jù)表。多表繼承
  • 改變?cè)赑ython層面上的一些model的行為,而不是model的字段。

Abstract base classes

from django.db import models
class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()
    class Meta:
        abstract=True
class Student(CommonInfo):
    home_group = models.CharField(max_length=5)
>>>abstract=True表明CommonInfo是一個(gè)抽象類,不在數(shù)據(jù)庫(kù)中建表,CommonInfo不能直接使用。同時(shí)Student與CommonInfo不能有名稱相同的屬性。Student由于繼承了CommonInfo,所有Student有三個(gè)字段name,age,home_group。如果子類中沒(méi)有定義Meta則其繼承父類的Meta。子類也可以擴(kuò)展父類的Meta

 class Meta(CommonInfo.Meta): db_table = 'student_info'

小心處理related_name and related_query_name
如果使用related_name和related_query_name使用在外鍵和多對(duì)多的關(guān)系中,必須制定一個(gè)唯一的名字。在抽象類中使用related_name和related_query_name需要與app_label和class標(biāo)記
'%(class)s'將會(huì)被子類小寫(xiě)名,而'%(app_label)s'會(huì)被子類所在的app小寫(xiě)名替代

common/models.py

from django.db import models
class Base(models.Model):
      m2m = models.ManyToManyField(OtherModel,
relate_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",)
      class Meta:abstract=True
class ChildA(Base):pass
class ChildB(Base):pass
>>>
common.ChildA.m2m的reverse name是common_childa_related
reverse query name是common_childas。如果不指定related_name則默認(rèn)為子類名+_set, ------>childa_set

Multi-table inheritance

from django.db import models
class Place(models.Model):
      name = models.CharField(max_lenght=50)
      address = models.CharField(max_length=80)
class Restaurant(Place):
      serves_hot_dogs = models.BooleanField(default=False)
      serves_pizza = models.BooleanField(default=False)
      place_ptr = models.OneToOneField( 
          Place,  
          on_delete=models.CASCADE, 
          parent_link=True,
    ) #與父類進(jìn)行一對(duì)一關(guān)聯(lián)
>>>
這種寫(xiě)法會(huì)在數(shù)據(jù)庫(kù)中創(chuàng)建兩個(gè)表,同時(shí)Restaurant擁有Place所有的字段
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class: >>> p.restaurant
<Restaurant: ...>

Proxy models

采用Multi-table inheritance的方式需要為每一個(gè)類創(chuàng)建一個(gè)數(shù)據(jù)表,比較耗資源。可以采用代理模型,可以對(duì)代理模型進(jìn)行數(shù)據(jù)操作,而反應(yīng)在原始模型上

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

>>> MyPerson和Person會(huì)操作同一個(gè)數(shù)據(jù)表
>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar") 
<MyPerson: foobar>

proxy model必須繼承一個(gè)非抽象model,proxy model還可以繼承一個(gè)proxy model共享一個(gè)非抽象model。如果沒(méi)有為proxy指定一個(gè)manager那么其將繼承父類的manager,如果定義了一個(gè)manager,那么這個(gè)manger稱謂proxy model的默認(rèn)manager。同時(shí)父類的manager照樣能夠運(yùn)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容