1. 程式人生 > 其它 >07Django Model三種繼承模型詳解

07Django Model三種繼承模型詳解

在 Django 中每個 Model 都是一個 Pyhton 類,前文之前提到過 Model 繼承自django.db.models.Model。通過類之間的繼承 Django 會對自定義的 Model 自動添加了兩個屬性分別是 id 和 objects。

在 Model 不指定主鍵的情況下,Django 會通過 AutoFiled 欄位型別將 id 設定為預設自增主鍵。這裡就不加贅述了,在本節我們將從另一個屬性 objects 講起,然後再深入瞭解 Model 的繼承模型。

1. objects查詢管理器

objects 是 Manager 類的例項物件,被稱為查詢管理器,是資料庫查詢的入口。每一個 Django Model 都至少有一個 Manager 例項,可以通過自定義建立 Manager 以實現對資料庫的定製訪問,這裡我們講到 Manager 類,它也同樣定義在 models 模組中,引入方式如下:

django.db.models.Manager

2. Model的繼承模型

Django Model 的繼承與 Python 類的繼承是一樣的,只是 Django 要求所有自定義的 Model 都必須繼承自 django.db.models.Model。在 Django 中 Model 之間有三種繼承模型,它們分別是抽象基類、多表繼承以及代理模型。

1) 抽象基類

抽象類繼承的作用是將子表中通用的欄位聚合在一起,並將這些欄位統一定義在抽象基類中,避免於重複定義這些欄位。抽象基類的定義通過在模型的 Meta 中定義屬性 abstract=True 來實現。示例如下:

from django.db import models
class AbstractBase(models.Model):
id = models.AutoField()
content = models.CharField(max_length=100)
username = models.CharField(max_length=80)
nowday = models.DateTimeField()
class Meta:
abstract = True
class SomeThing(AbstractBase):
testexams = models.CharField(max_length=50)
class SomeComment(AbstractBase):
level = models.CharField(max_length=20)

  

本例中 3 個類對映到資料庫後,但會被定義為兩個資料表。 分別是 SomeThing 與 SomeComment 它們都繼承自AbstractBase,且繼承了父表中的所欄位值,同時自身又自定義了新的欄位。所以,它們對應的欄位分別如下所示:

  • SomeThing 資料表:有 id、content、username、nowday、testexams 等 5 個欄位;
  • SomeComment 資料表:有 id、content、username、nowday、level 等 5 個欄位。


關於 Model 的元資料繼承關係,遵循以下幾個規則:

  • 抽象基類中定義的元資料,子類中沒有定義,子類會繼承基類中的元資料;
  • 抽象基類中定義的元資料,子類也定義了,子類優先順序更高;
  • 子類可以定義自己的元資料,即不出現在抽象基類中的元資料。


在定義抽象基類時,需要注意,如果定義了 ForeignKey 或 ManyToManyField 型別的欄位,並且設定了 related_name 或者 related_query_name 引數,由於繼承關係,子類也會擁有同樣的欄位,所以,在子類中的反向名稱和查詢名稱是唯一的。

2) 多表繼承

這是 Django 支援的第二種繼承方式,因為每個類都是一個完整的 model,而不屬於抽象基類,所以父 model 和子 Model 都會有資料庫表,而且 Django 預設會給和子表和父表之間自動建立一個 OneToOneField 資料表關係,並且該欄位將作為子表的主鍵。示例如下:

  1. from django.db import models
  2. class a(A):
  3. testname=models.charFiled(max_length=255,help_text="測試")

如果你想指定連結父類的屬性名稱,你可以建立你自己的 OneToOneField 欄位,並且設定 parent_link=True 從而使用該欄位連結父類。

多表繼承與抽象基類有一個顯著的不同點是 Meta 內部類的繼承:子類不會繼承父類的 Meta 定義。但是,有兩個 Meta 元資料項比較例,它們分別是 ordering 和 get_latest_by,它們是會被子類繼承的,所以,如果不想讓它們影響子類的行為,應該覆蓋這兩個元選項。比如父類有了排序設定,而你並不想讓子類有任何排序設定,你可以使用如下方式來禁用子類的排序:

  1. class ChildModelName(ParentModelName):
  2. class Meta:
  3. ordering = []#子表將不會排序

3) 代理模型

代理模型用來給父 Model 新增一些方法或者修改其 Meta 選項,但是父 Model 的欄位定義不會被修改。我們可以理解為對原父 Model 進行了 Copy,而被 Copy 出來的 Model 就叫做父 Model 的代理模型,但是這個代理模型又有其自己的特點,這相當於 Python 面向物件中的類繼承與多型。

這裡需要注意的是代理模型不會在資料庫中建立新的資料表,它將使用父 Model 的資料表,即對代理模型的CURD操作將會作用到原始的Model 中。


那麼如何建立代理模型呢?在 Meta 類中為我們提供了 proxy 選項。在《Django Meta元資料類屬性解析》一節我們曾提到過這個選項,將其設定為 True 即表示建立代理模型。我們通過 BookStore 專案示例進行說明:

class BookExtend(Book):
"""
BOOK代理模型
"""
class Meta:
ordering=['id'] #定義Meta選項順序排序按照id欄位
proxy=True #設定代理模型
def __str__(self):
return "title:%s pub:%s price:%s" % (self.title, self.pub, self.price) #定義方法

  

新增完上述程式碼,然後執行資料庫遷移操作。通過檢視 MySQL 資料庫可以看到並沒有新建 BookExtend 資料表。如下所示:

mysql> show tables;
+----------------------------+
| Tables_in_bookstoredb      |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
| index_author               |
| index_author_books         |
| index_book                 |
| index_extenduserinfo       |
| index_pubname              |
| index_userinfo             |
+----------------------------+
16 rows in set (0.00 sec)

提示:最後需要注意的是代理只能繼承自一個非抽象的基類,並且不能同時繼承多個非抽象基類。

原文:http://c.biancheng.net/view/7640.html