📚 Django - Data Modelling
Create Model
- 會自動產生 primary key,因為繼承自 models.Model。若想要自訂
primary key
,可以參考 sku 的寫法
Choices
field
One-to-One
relationship
on_delete=models.CASCADE
(層級刪除): 當父模型被刪除時,與之相關聯的子模型也會被刪除on_delete=models.PROTECT
(保護模式): 防止刪除父模型,除非先刪除所有與之相關的子模型。on_delete=models.SET_NULL
(設為空值): 當父模型被刪除時,與之相關聯的子模型的外鍵欄位(即OneToOneField
)會被設為 NULL。- 範例:一個簡單的部落格系統,如果一篇文章被作者刪除,該文章的作者欄位會被設為 NULL。
on_delete=models.SET_DEFAULT
(設為預設值): 當父模型被刪除時,與之相關聯的子模型的外鍵欄位會被設為預設值。- 範例:一個簡單的部落格系統,如果一篇文章被作者刪除,該文章的作者欄位會被設為 NULL。
on_delete=models.SET()
(設定為特定值): 當父模型被刪除時,與之相關聯的子模型的外鍵欄位會被設為特定的值(通常是另一個存在的模型實例)。- 範例:一個論壇系統,如果一個用戶帳號被刪除,與之相關聯的文章的作者欄位會被設為論壇的預設用戶,這個預設用戶的 ID 為 1。
One-to-many
relationship
one collection can have many products
-
Use
foreignkey
-
if you can not modify the order of declaration for the
collection
model, you can employ astring argument
within theForeignKey
field:collection = models.ForeignKey('Collection', on_delete=models.PROTECT)
Many-to-Many
relationship
- Use
ManyToManyField
- to customize the name of the reverse relation. Instead of the default
product_set
, you can use therelated_name
field
Generic
Relationship
-
ContentType
(內容類型): 在 Django 中,ContentType
是一個模型,它用來表示其他模型的類型。在這個程式碼中,content_type
欄位是一個外鍵,關聯到ContentType
模型。這麼做的好處是,它允許你動態地參照其他模型,而不是在程式碼中直接寫死模型的名稱。這樣的設計可以增加彈性,讓你的程式碼更容易擴展和修改,而不需要改動太多程式碼。 -
GenericForeignKey
(通用外鍵):GenericForeignKey
是一個用於關聯任意模型的特殊欄位。在這個例子中,content_object
欄位使用了GenericForeignKey
。這意味著LikeItem
模型可以與任何其他模型建立關聯,而不僅僅是固定的一個或幾個模型。通過content_type
和object_id
這兩個欄位,你可以動態地建立與不同模型的關聯。 -
LikeItem
模型:LikeItem
是一個用戶點贊的模型,它關聯到了使用者 (user
) 和其他模型 (content_type
和object_id
確定的模型)。這樣的設計允許你在不確定具體模型的情況下,保存用戶對不同類型物件的喜愛。
在 LikeItem
模型中,content_type
是一個外鍵欄位,關聯到 ContentType
模型,用來指定被點贊物件的類型(例如,是一篇文章還是一張圖片等等)。而 object_id
是一個正整數欄位,用來指定具體的被點贊物件的 ID。
GenericForeignKey
的作用就是把 content_type
和 object_id
這兩個欄位關聯到一個具體的模型實例上,這樣你就可以在 LikeItem
中使用 content_object
這個屬性,直接訪問被點贊的具體物件,而不需要關心它是哪種模型。
例如,如果 content_type
指定為文章,object_id
指定為某篇文章的 ID,那麼 content_object
就可以直接訪問該篇文章的所有屬性和方法。這樣,你可以在不確定具體模型的情況下,動態地建立關聯,使得程式碼更加靈活和可擴展。
你可以將 content_object
想像成程式語言中的指標 pointer
。在這個上下文中,content_object
實際上是一個通用指標,指向了應用中的任何一個模型的特定實例。這樣的設計使得你可以動態地指向和訪問不同模型的物件,而不需要知道具體是哪個類型的物件。
就像指標在程式語言中可以指向不同的變數或數據結構,content_object
允許你在 LikeItem
模型中指向任何類型的物件,從而實現彈性的資料模型。這樣的抽象設計使得程式碼更具通用性,可以應對多種不同的情況,同時也使得程式碼更容易擴展和維護。
Generic Relationship - Example
假設你的對象是 Article
(文章)模型,你可以使用 GenericForeignKey
來建立 LikeItem
與 Article
之間的關聯。以下是一個簡單的範例:
首先,定義你的 Article
模型:
然後,定義你的 LikeItem
模型,使用 GenericForeignKey
來建立通用外鍵關聯:
在這個例子中,LikeItem
模型可以關聯到任何模型的實例,包括 Article
。當你想要為某篇文章建立一個 LikeItem
時,你可以這樣做:
在這個例子中,content_type
指定為 Article
模型的類型,object_id
指定為具體文章的 ID。通過 GenericForeignKey
,你可以使用 content_object
直接訪問到被點贊的文章的屬性。這樣,你可以動態地建立與不同模型的關聯,而不需要為每種模型都定義一個單獨的外鍵。
Reverse Relationship - Example
在 Django 中,反向關係(reverse relationship) 通常是自動產生的,無論是在一對一(One-to-One)、一對多(One-to-Many)還是多對多(Many-to-Many)的關係中,Django 都會自動為你建立反向關係。這意味著你可以從一個模型對象訪問與之相關聯的其他模型對象。
假設你有兩個模型,一個是Author
,另一個是Book
。Book
模型有一個外鍵欄位指向Author
模型:
在這個例子中,Book
模型有一個外鍵欄位author
指向Author
模型。Django 會自動為Author
模型生成一個反向關係。這意味著你可以透過Author
模型來訪問所有與之相關聯的書籍,即使你並沒有在Author
模型中定義相關的欄位。
例如,如果你有一個Author
的實例author
,你可以這樣獲取所有與這個作者相關的書籍:
在這裡,book_set
就是 Django 自動為Author
模型生成的反向關係。這個名稱的格式是小寫的模型名稱_set
,它可以讓你訪問到所有與這個模型相關的對象。這種反向關係的自動生成使得在 Django 中進行模型之間的查詢和操作更加方便。
然而,有一個特殊的情況是如果你已經使用了 related_name
參數來定義了自定義的反向關係名稱,反向關係的名稱就不再是默認的 小寫的模型名稱_set
格式。在這種情況下,你必須通過自定義的名稱來訪問反向關係。
舉例來說:
在這個例子中,Passport
模型有一個一對一的外鍵關係,並且使用了 related_name='passport'
參數。這樣,在 Person
模型中就不會自動生成默認的反向關係。要訪問這個關係,你需要使用 passport
這個自定義的名稱:
在其他情況下(包括一對多和多對多關係),Django 都會自動生成默認的反向關係,你可以直接使用模型的名稱(小寫)作為反向關係的名稱。
related_name
field in ForeignKey
在一對多關係中,related_name
可以被用來定義反向關係的名稱,使你能夠更具意義地訪問相關對象。在多對多關係中,related_name
可以被用來定義通過中間表訪問相關對象時的名稱。
以下是一個一對多和多對多關係中 related_name
的使用示例:
一對多(One-to-Many)關係:
在這個例子中,Book
模型的 author
欄位定義了外鍵關係,並且使用了 related_name='books'
參數。這樣,你就可以透過 author.books.all()
來訪問一位作者的所有書籍。
多對多(Many-to-Many)關係:
在這個例子中,Person
模型和 Group
模型之間建立了多對多的關係。Person
模型的 groups
欄位使用了 related_name='memberships'
參數。這樣,你可以透過 group.memberships.all()
來訪問一個群組中的所有成員。