Django - Models

Django 所採用的模式是 MTV 模式

上週介紹的 Views 文章有提到 MTV 模式,我們再來複習一下

使用者瀏覽網頁時,伺服器的運作流程如下:

MTV

urls.py 會將 request 傳送至 View

View 收到 request,處理過程中需要資料庫的資料時,就會向 Model 要資料

Model 收到 View 來的指令,將處理好的資料給 View (* Model 不是代表資料庫,而是 負責與資料庫溝通 的一個 Layer )

View 收到資料後,將資料做最後的處理

View 拿 Template 的東西來進行 render,最後由 View 回應給使用者

Model

我們這週要來介紹的是 Model

當我們需要處理資料時,就會需要 Model

Model 並不是只資料庫,而是跟資料庫溝通的一層 Layer

我們先來了解什麼是 ORM

ORM

Django 採用 ORM 來處理資料,ORM 全名為 Object Relational Mapping

原本我們要使用 SQL 語法 跟資料庫溝通

不過 ORM 讓我們可以用 物件 的方式來處理資料

假設我想看某個 table 的所有資料

我必須要用 SQL 語法來查詢

1
SELECT * FROM table_name;

但如果是用 Django 的 ORM 語法呢?會簡單易懂許多

1
User.objects.all()

了解了 ORM 語法後,我們可以先來看一下該怎麼定義 table 以及 column

models.py

我們會將要定義的 table 以及 column 放在 models.py 這個檔案之中

fields

在 Django 的手冊中指出,每個 model 都是 class,因此可以繼承 django.db.models.Model 的特性

Each model is a Python class that subclasses django.db.models.Model

所以第一件事就是用 class 的方式定義 table

並在該 class 中定義屬性,這些屬性代表 table 中的 column ,在 Django 稱作為 field

Each field is specified as a class attribute, and each attribute maps to a database column.

我們要先 import models,讓 class 去繼承 models 中的 Model

接著定義 table 的名稱以及屬性

1
2
3
4
from django.db import models

class User(models.Model):
name = models.CharField(max_length=20, default="")

理解基本的 table 以及 column 定義後,我們可以來點關聯!

one to one

有些資料會有一對一的關聯,舉例來說

除了基本 User 資料,需要有另一個 Model 來存個人資訊,像是 地址 / mail / 電話等等

這時候 User 與個人資料 table 就會有一對一的關聯

該怎麼做呢?

ForeignKey

當我們知道一個 User 會有一個 Profile 之後,

就可以用 關係 來想看看 ForeignKey 設定該放在哪裡

通常我們會將 Foreign Key 放置在「屬於」的 Model 中

以剛剛的例子來說,是 Profile 會 屬於 一個 User

所以我們會將 ForeignKey 放在 Profile 該 table 中

ForeignKey 就像是一條線索, Profile 會透過該線索,去找到 User

one to one

接著我們就來把它轉變成程式碼吧!

在 ForeignKey 中有幾個必填的參數

class ForeignKey(to, on_delete, **options)

第一個參數是 ForeignKey 會指向哪個 model

第二個參數 on_delete 意思是當 關聯 model 的資料被刪除時,要做什麼事,這邊我們設定成 models.CASCADE ,代表當 User 被刪除時,跟該筆有關的 Profile 都會被刪除

第三個參數是為了一對一的關聯而設定的,我們希望一筆 User 只對應一筆 Profile ,對於 Profile 來說,每一個 User 的 id 都是獨特的,不可重複

(如果沒有設定這個參數,那就會變成 User 可以有多筆 Profile 囉)

1
2
3
4
5
6
7
8
9
from django.db import models

class User(models.Model):
...


class Profile(models.Model):
...
user = models.ForeignKey(User, on_delete=models.CASCADE, unique=True)

OneToOneField

Django 也有提供更明確的一對一關聯方法,

也就是 OneToOneField

這個方法會會直接在 Profile 中增加一個欄位,存放 Foreign Key (也就是 User 的 id )

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models

class User(models.Model):
name = models.CharField(max_length=10)
age = models.IntegerField()


class Profile(models.Model):
email = models.CharField(max_length=10, default="")
address = models.CharField(max_length=50, default="")
phone = models.CharField(max_length=10, default="")
user = models.OneToOneField(User, on_delete=models.CASCADE)

上述兩種方法都可以建立一對一的關聯,

相較於 ForeignKey 的方式,OneToOneField 在程式碼中會顯得更易讀明確

many to one

再來就是稍微複雜的關聯,多對一,

舉例來說,今天一個 User 會有多筆 Order

但一筆 Order 只能對應一個 User

這時候就會形成 多對一 的關聯

我們來看一下該怎麼設定

ForeignKey

就像剛剛舉例的,我們會將 Foreign Key 放在 「屬於」 的 table

這次的例子是 多筆 Order 會屬於一個 User

所以我們會將 ForeignKey 該設定放在 Order 中

我們直接用圖片來理解比較快

many to one

理解了多對一的關係後,我們就可以來轉變成程式碼了

跟剛剛的一對一不同,這時每個 Order 的 User 是可以重複的,所以我們不需要加上 unique=True

1
2
3
4
5
6
7
from django.db import models

class User(models.Model):
...

class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)

many to many

再來就會更複雜一點,也就是多對多的關聯

舉例來說,使用者與群組的關聯,

一個使用者可以參加多個群組,

而一個群組可以擁有多個使用者,

這時候就會形成多對多的關聯

many to many

ManyToManyField

Django 提供了我們 ManyToManyField 的方法

這次的關係是 一個使用者可以 屬於 多個群組 且 一個群組可以 屬於 多個使用者

不過通常多對多的關係,都會用第三方表格來存放雙方的關聯

所以 ForeignKey 會放在第三方表格中

而 User 及 Group 則是要設定 ManyToManyField 以及 through 參數,

當你需要用 User 去查詢 Group 的時候就會比較方便,不需要透過第三方表格

  • 屬性的定義 是要用複數,不然會跑出提醒你要改名的錯誤訊息
  • User 在建立的時候,Group 還不存在,因此要用字串來取代
1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models

class User(models.Model):
groups = models.ManyToManyField('Group', through="UserGroup")


class Group(models.Model):
users = models.ManyToManyField(User, through="UserGroup")

class UserGroup(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)

雖然多對多的關係可以在第三方表格用 ForeignKey 來設定關聯,

但如果沒有透過 ManyToManyField

在查找資料的時候就都得透過第三方表格,其實蠻不方便的

所以還是要設定 ManyToManyField 以及 through 參數唷

基本的關聯差不多都介紹完了,接下來就剩怎麼將定義變成資料庫中的 table 以及 column

migration

當我們將 table 及 column 都設定好之後,就可以來做 migration 啦

migration 是什麼呢?

我們可以把它想像成是 Database 的歷史紀錄

有任何的更動都會被記錄在 migration 中

在 Django 中,我們只要下

1
python manage.py makemigrations

就會依照更動來做出新的 migration 囉

migrate

當 migration 做完,我們就該來改變資料庫的 table 以及 column

這時候就需要下

1
python manage.py migrate

資料庫這時候就會依據設定改變了

狀況題:如果 migrate 之後,又要做更動該怎麼辦?

只要動到 models 這個檔案,再重新做一次 makemigrations 再 migrate 就可以了

狀況題:如果需要更改 migration 的時候該怎麼辦

在 Django 中,有可以讓我們 rollback 的指令

什麼是 rollback 呢?可以把它想像成是鍵盤的 ctrl + z 復原鍵

我們要將 migration 復原可以下該指令

1
python manage.py migrate YOUR-APP-NAME YOUR-ROLLBACK-MIGRATION-NUMBER

這時候就可以進行復原

以上是基礎的 Django model 使用介紹

如果還有狀況題想要提出討論,歡迎在底下留言,會傳送到我的 github 作為 issue 通知我,屆時可以一起討論

如果有幫助的話也歡迎按讚 ヾ(´∀ ˋ)ノ