1. 程式人生 > >00x: Django models.Model詳解

00x: Django models.Model詳解

Models
model是對於資訊的一種模型封裝與定義。它包含了你要儲存的必要欄位和操作資料的方法。一句話概括就是,每個模型映射了一張資料表。
基本概念:

每個model都是繼承於django.db.models.Model 的Python類。

model的每一個屬性對應資料表中的一個欄位。

通過所有的這些,Django提供了一個自動化生成訪問資料庫的API。

簡單例項
這個例子定義了Person ,並給它賦予了first_name 和last_name:
在這裡插入圖片描述
其中first_name 和last_name 是model的欄位。如你所見,每一個欄位被定義為class類的一個屬性,而每個屬性對應著資料庫的一列。

上面的建立Person ,model模型的過程用SQL語句翻譯過來如下:
在這裡插入圖片描述
下面是一些需要注意的問題:

資料表的名字,myapp_person,自動繼承一些model的metadata設定,但是同時支援自定義。

id欄位是自動新增的,但是它同樣可以自定義。

CREATE TABLE這個SQL語句在這個例子中由PostgreSQL來實現,

使用models
一旦你定義好了你的模型,你需要告訴Django你將要使用這些models。這就需要秀修改工程目錄下的settings.py檔案。假設你的model定義在了app名為myapp的models.py 檔案中,為了使得Django識別出你要使用這個model,你就需要在settings.py中設定如下:
在這裡插入圖片描述


當你新增新的APP到INSTALLED_APPS中時。需要執行命令python manage.py migrate使設定生效。可供選擇的是為了使用git等程式碼管理軟體,你可以先執行python manage.py makemigrations。

欄位
model最重要的部分而且也是model所需的基礎部分是它定義的資料庫欄位的集合。欄位由類的屬性來定義。需要注意一點,不要使用和models API衝突的名字來命名欄位例如clean,save或者delete。

例子:

在這裡插入圖片描述
欄位型別
你模型中的每一個欄位應該是一個Field類的例項。Django使用欄位類來決定一些事:

列的型別,就是告訴資料庫要儲存的資料型別是什麼。

預設的HTML外掛 ,用以渲染表單欄位(例如,)

基本的驗證需求,在Django的admin中和自動生成的表單中使用。

Django自帶了很多內建的欄位型別。若Django沒有你想要的型別,你可以自己實現。

欄位選項
每一個欄位使用一個確定的欄位宣告引數集合。例如,CharField(還有它的子類)需要一個max_length引數來宣告資料庫用於儲存欄位VARVHAR的個數。

同樣的,還有其他的一些選項可用來設定欄位,它們都是可選的。下面介紹幾個比較常用的設定選項:

null:
若為True,Django會把空資料使用NULL儲存在資料庫中。預設是False。
blank:
若為True,該欄位允許為空。預設是False。
注意它和null的不同。null是純粹和資料庫相關的,而’blank’則是和驗證相關的。若一個欄位的blank=True,表單的驗證將會允許例項帶一個空值。反之則不行。
choices:
一個可迭代的元祖,用來作為欄位內容的選擇。若這個給定,預設的表單外掛將會變成一個單選框而不是簡單的文字欄位,並且單選框中的選項數目由給定的choices來限定。
一個標準的choices列表和下面的形式類似:
在這裡插入圖片描述
每個元組中的第一個元素是要儲存在資料庫中的內容。第二個元素用於在顯示的控制元件上展示。

給定一個model的例項,用於顯示的choices的值可以通過使用get_FOO_display()方法來獲取,例如:
在這裡插入圖片描述
在這裡插入圖片描述

default:
這個選項用於設定該欄位的預設值。可以是一個值或者可以是一個可以呼叫的物件。若是可呼叫的物件,它會在每次新物件建立的時候呼叫。
help_text:
額外的幫助文字用於顯示在widget上。它對文件的生成很有用。
primary_key:
若為True,該欄位會作為這個model的主鍵。如果你沒有為其他欄位宣告primary_key=True,Django會自動地新增一個IntegerField欄位作為主鍵。所以如果沒有特殊需求,這個選項可以不做設定。
主鍵的欄位是隻讀的。如果你改變了現有物件的主鍵的值然後儲存了這個物件,一個新的物件就會和舊的物件並行建立。啥意思呢?如下面的例子所示:
在這裡插入圖片描述
在這裡插入圖片描述
unique:
若為True,該欄位必須是整張表中獨一無二的

自動主鍵欄位
預設情況下,Django給每個模型以下欄位:
在這裡插入圖片描述
這是一個自動新增的自增主鍵。
如果你想宣告一個典型的主鍵,只需要在對應的欄位選項中設定primary_key=True。若Django看到你顯式聲明瞭自定義的主鍵,那麼Django就不會為你建立一個自增的id欄位。
每個模型需要明確一個欄位作為主鍵。

verbose欄位
除了ForeignKey,ManyToManyField和OneToOneField,每個欄位都有一個可選的設定引數:詳細。若這個選項未給定,Django會使用屬性名來定義,用下劃線分隔。
下面的例子中,verbose的名稱是”person’s first name”
在這裡插入圖片描述

下面的例子中,verbose的值為”first name”:在這裡插入圖片描述
ForeignKey,ManyToManyField和OneToOneField需要第一個引數為model類物件,所以如果要使用verbose_name,需要顯式地宣告:

在這裡插入圖片描述
一個慣例就是verbose_name的第一個字母一般不寫成大寫的形式。Django將會自動地將需要首字母大寫的地方大寫。

資料庫關係
Django提供了用來描述三種資料庫關係的方法,分別是:many-to-one,many-to-many和one-to-one。

Many-to-one
使用django.db.models.ForeignKey來定義Many-to-one這種關係。這個類的使用和其他欄位的定義一樣,也是作為一個屬性存在。
ForeignKey需要一個位置指示引數:當前model相關聯的class類名。
例如,Car 和Manufacturer(製造商)。每個Manufacturer都會製造很多Car,但是每輛Car只屬於一家Manufacturer,這樣的關係就稱為多對一關係。基於此例子,程式碼可以編寫如下:
在這裡插入圖片描述
關於ForeignKey更加詳盡的定義連結如下。

Many-to-many
舉個例子,每個Pizza物件都有多個Topping物件,而多個Topping物件則可以在多個Pizza餅上。程式碼如下:
在這裡插入圖片描述
————(複雜的多對多情況遇到的時候再補充)—————–

One-to-one
例如,如果你構建了一個名為places的資料庫,你應該在資料庫中構建相對標準的東西例如地址,電話號碼等。然後,如果你想在places的基礎上建立一個restaurants 的資料表,這時你就可以直接使用places 所定義好的部分,使用的方式就是一種one-to-one的模式。

跨APP的model呼叫
如果當前app下models.py 檔案中的程式碼想要呼叫另外一個app中models.py中的model,這也是可以的。做法就是在當前檔案中以匯入類的方式匯入你想要使用的外部的model,然後直接使用即可:
在這裡插入圖片描述
欄位的名稱限定
Django對於欄位的限制有兩個:

  • 欄位的名稱不能為Python的關鍵字,這個比較好理解,舉例如下:
    在這裡插入圖片描述
    欄位的名稱不能包含超過兩個下劃線,因為這會與Django查詢語法起衝突。
    在這裡插入圖片描述
    SQL的一些保留字如`join,where,select則是可以在model的欄位名稱中使用的,因為Django在每次SQL查詢中避免了可能發生的衝突。

自定義欄位型別
如果現有的欄位無法滿足你的需求,你也可以自定義欄位。具體的細節參考此連結。

Meta選項
通過使用內部類Meta來設定model的元資料,例子如下:
在這裡插入圖片描述
Model的元資料是“任何非欄位的資料”,例如ordering的選項,資料表名字(db_table),或者人類可讀的單複數名稱(verbose_name和verbose_name_plural)。這些都不是Model所必需的,是可選項。
更多關於Meta的選項點選此連結。

Model屬性
objects:
model最重要的屬性是Manager。它是提供給Django的資料庫查詢操作的介面,用於從資料庫中獲取model例項。若非特別宣告Manager,它預設的名字為objects。Manager只能通過model類進行訪問,不能通過model例項進行訪問。

Model方法
為model的物件操作定義一般的“row-level”功能。而Manager方法是對於整張表操作的方法。model的方法應該作用於某一特定的model例項上。
對於使得業務邏輯的統一來說這是一項很有價值的技術。
例如,下面的model有一些常用方法:
在這裡插入圖片描述
本例中的最後一個方法是一個property。
model例項有很多方法的介面,你可以通過重寫這些方法來實現自己想要的功能:
str():
Python的”魔力函式“,該函式返回一個表示當前物件的字串。適用於Python或者Django用於將例項顯示為純字串的形式,這樣的情形往往會出現在互動的命令列視窗或者在admin頁面中。
get_absolute_url():
該函式告訴Django如何計算一個物件的url。Django
在admin介面中使用該函式,在需要的時候返回物件的url。

覆寫預定義的模型方法
還有一些其他方法封裝了一些你可能會使用到的資料庫操作。尤其是save()和delete()方法比較常用。
你可以自由覆寫這些方法來獲得自己想要的資料庫操作。
一個典型的使用情景是如果你想要在儲存物件到資料庫的時候做一些事情,就可以覆寫實現。以save()函式為例:
在這裡插入圖片描述
不要忘記在覆寫的時候呼叫父類的方法super().save(*args,**kwargs),這樣可以確保物件可以儲存到資料庫中。如果你忘記了呼叫父類的方法,那麼所有的操作都不會資料庫中生效。

在shell中對資料庫進行操作
Django提供了一個命令列工具,可以將當前專案下的環境,遷移到當前工作環境下。

在建立了model之後,可以在shell中對model進行操作,執行以下語句,進入shell:
python manage.py shell
執行後,進入python命令列模式,此時就可以在這裡對你建立的model進行操作了。
假設我們建立了兩個model,定義如下:

在這裡插入圖片描述
資料的插入
在這裡插入圖片描述
以上程式碼執行後,會在mysql資料庫的myapp_grades資料表中插入一條資料。

資料的修改
在這裡插入圖片描述

資料的刪除
在這裡插入圖片描述

關聯物件
在這裡插入圖片描述

關聯物件 下,對於獲取關聯物件的機集合,有兩個主要任務:

獲得一條Grades資料所對應的所有學生Student
獲得Student所對應的班級Grade

Model繼承
Django中Model的繼承方式幾乎和Python中類的繼承方式幾乎一樣。所有的model都繼承於例項django.db.models.Model。
你需要做的決定僅僅是你的父類model的角色:是作為一個抽象類,給子類提供一個通用部分的描述?還是直接作為例項,擁有自己的資料表?以下是三種最常用的類繼承模式:

通常情況下,我們只想使用父類來儲存一些你不想在每個子類中都敲一遍的通用資訊。該類不會真正對資料庫操作,也就是所謂的抽象基類。
如果你繼承了一個現存的模型(可能來自於另外一個app例項)並且想要每個model都有自己的資料表,Multi-table inheritance就是這樣做的。
最後,如果你只是想要修改Python語言級別的model行為而不修改models的欄位,你可以使用Proxy models
抽象基類
抽象基類在你想要在你的模型中加入一些資訊的時候很有用。在元資料中將基類的引數abstract=True,這樣,該model就不會被用來建立任何資料表。當它被其他model作為基類時,它的欄位將會作為繼承它基類的欄位。子類中的欄位名不能和基類中的欄位名一樣,否則會報錯。下面是一個例子:
在這裡插入圖片描述
Student模型有三個欄位,分別是name,age和home_group。
CommonInfo模型不能被用作是一個正常的Django模型,因為他是一個抽象基類,它不會生成資料庫表或者有manager,不能被直接例項化或者儲存。

Meta繼承
當一個抽象基類被建立的時候,Django會宣告一些Meta 內部類,若子類沒有宣告它自己的Meta類,它就會繼承父Meta。如果子類想要拓展父Meta類,需要先繼承,再拓展:
在這裡插入圖片描述
Django對於抽象基類Meta類做了調整:在使用Meta屬性的時候,會設定abstract=False 。這意味著抽象基類的子類不會自動變成抽象類,除非你自己手動將其設定為True,讓其成為抽象類。