Django筆記七之ManyToMany和OneToOne介紹

来源:https://www.cnblogs.com/hunterxiong/archive/2023/03/24/17253517.html
-Advertisement-
Play Games

該工程為在保存時執行開發的功能,函數入口點ufput。其他還有新建、打開、另存等都可以加入開發的操作,具體看UF_EXIT下的介紹。 用戶出口是一個可選特性,允許你在NX中某些預定義的位置(或出口)自動運行Open C API程式。如果你進入其中一個出口,NX會檢查你是否定義了指向Open C AP ...


ManyToMany 是一種多對多的關係,在用途和使用方法上和外鍵 ForeignKey 類似。

以下是本篇筆記的目錄:

  1. ManyToMany 的介紹
  2. through 參數
  3. through_fields 參數
  4. ManyToMany關係數據的增刪改查
  5. OneToOne介紹

1、ManyToMany 的介紹

假設有兩個 model,Person 和 Group,這兩個model之間是多對多的關係。那麼我們可以如下創建其關係:

# blog/models.py

class Person(models.Model):
	name = models.CharField(max_length=64)

class Group(models.Model):
	name = models.CharField(max_length=64)
	members = models.ManyToManyField(Person)

通過上述代碼我們就創建了有多對多關係兩個model,當我們執行 migrate 操作之後(可以先不執行,後續還會對其有所更改),系統除了會創建 Person 和 Group 這兩個表之外,還會創建一個表。

表名為 blog_group_members,因為是放在 Blog 這個 application 下麵,所以,表名的首碼是 blog,然後加上 model 名的小寫為 group,加上欄位名稱 members。

這張第三方表會有兩個欄位,person_id 和 group_id,將這兩個 model 關聯起來。

通過往這張第三方表寫入 person_id 和 group_id的數據,我們就將這兩個 model 關聯了起來。

而獲取他們對應的關係的記錄和 ForeignKey 的關係類似:

根據 Person 數據查詢關聯的 Group 數據:

person = Person.objects.get(id=1)
group_list = person.group_set.all()  # 使用 Group 的小寫加 _set

根據 Group 數據查詢關聯的 Person 數據,這個查詢方法略微不同,用到的是 Group 定義的 members 欄位:

group = Group.objects.get(id=1)
person = group.members.all() 

# 根據條件來搜索 person 也是可以的
person = group.members.filter(name='hunter')

2、through參數

上面 ManyToMany 的定義中,我們沒有加任何參數,所以自動創建的表名是預設的,欄位也只是兩個 model 的主鍵id。

而如果我們有一些額外的需求,比如說,為 Person 和 Group 添加關聯關係時,需要加上關聯時間,或者想自己指定表名或 model 名的時候,我們可以通過 through 屬性來指定 model 的名稱,然後為其添加我們需要的欄位。

比如我們想為 Person 和 Group 創建一個多對多的關係,指定model 名為 Membership,且額外添加欄位,比如添加時間,可以通過 through 參數來指定:

class Person(models.Model):
    name = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(
        Person,
        through='Membership',
    )

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    

3、through_fileds參數

在我們上面創建的 Membership model 中,我們對應的多對多的欄位分別是 person 和 group,所以系統可以自動找到對應的多對多的欄位。

如果在第三方表,也就是 Membership 中,有多個相同的 Person 或者 Group 的欄位,就需要通過 through_fields 參數來指定多對多的欄位:

class Person(models.Model):
    name = models.CharField(max_length=50)


class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(
        Person,
        through='Membership',
        through_fields=('group', 'person'),
    )


class Membership(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    inviter = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        related_name="membership_invites",
    )
    invite_reason = models.CharField(max_length=64)

4、ManyToMany關係數據的增刪改查

接下來,我們定下最終的幾個 model 內容如下,用於演示 ManyToMany 的增刪改查的操作:

class Person(models.Model):
    name = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(
        Person,
        through='Membership',
    )

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)
    

現在我們有 Person 和 Group 兩個model,還有兩個 model 之間的關係表 Membership,如果我們要創建一個對應的關係,則需要創建一個 Membership 實例。

創建

首先創建 Person 和 Group 的記錄:

from blog.models import Person, Group, Membership
hunter = Person.objects.create(name='hunter')
group_1 = Group.objects.create(name='group_1')

創建多對多記錄:

m1 = Membership.objects.create(person=hunter, group=group_1, date_joined='2022-01-01', invite_reason='xxx')

根據單個 Person 記錄獲取所有相關 Group 記錄,使用方法同外鍵搜索方法:

groups = hunter.group_set.all()

根據單個 Group 記錄獲取所有相關 Person 記錄,根據多對多欄位來搜索:

persons = group_1.members.all()

根據 Membership 關係記錄獲取 Person 和 Group 記錄,可以直接用外鍵的的方式使用:

m1.person
m1.group

根據 Group 使用 add 添加一條多對多記錄:

paul = Person.objects.create(name='pual')
group_1.members.add(paul, through_defaults={'date_joined': '2022-01-01'})

其中,through_defaults 參數為字典,內容為多對多關係表的額外添加的欄位。

根據 Group 使用 create 創建一條多對多記錄:

如果沒有相應的 Person 記錄,可以根據 Group 來直接創建

group_1.members.create(name='mary', through_defaults={'date_joined': '2022-01-01'})

根據 Group 使用 set 刷新多對多記錄:

使用 set 方法來設置多對多的關係:

jack = Person.objects.create(name='jack')
lucy = Person.objects.create(name='lucy')
group_1.members.set([jack, lucy], through_defaults={'date_joined': '2022-01-01'})

需要註意的是,使用 set() 方法加上關聯之後,這個 Group 實例之前設置的關聯數據都會被清除。

也就是說,set() 里設置的關聯數據就是最終所有的關聯數據。

根據 Group 使用 remove 刪除一條多對多記錄:

在上面 我們使用了 set() 方法設置了兩條關聯數據,jack 和 lucy,現在我們想要把 jack——group_1 這條關係刪除,可使用 remove() 方法:

group_1.members.remove(jack)

使用 clear 清除某個 Group 實例上所有關係:

group_1.members.clear()

多對多的搜索:

根據 Person 的條件搜索 Group 的數據:

比如搜索 Person 的 name 欄位為 'hunter' 的 Group 數據

Group.objects.filter(members__name='hunter')

根據 Group 的條件搜索 Person 的數據:

比如搜索 Group 的 name 欄位為 'group_1' 的Person關聯數據:

Person.objects.filter(group__name='group_1')

如果要搜索額外的關聯欄位:

Person.objects.filter(group__name='group_1', membership__date_joined='2022-01-01')

5、OneToOne 介紹

不同於 多對一和多對多的關係,OneToOne 是一對一的關係,也就是說 一條數據僅能被另一條數據關聯。

下麵是兩個 OneToOne 對應的 model:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

    def __str__(self):
        return "%s the place" % self.name


class Restaurant(models.Model):
    place = models.OneToOneField(Place, on_delete=models.CASCADE, default=None, related_name='place_restaurant', null=True)

接下來創建兩條數據:

r_1 = Restaurant.objects.create()
p_1 = Place.objects.create(name='beijing', address='beijing')

根據 Restaurant 獲取 Place 數據,直接根據欄位獲取數據:

r_1.place

如果根據 Place 獲取 Restaurant 數據,因為是 OneToOne 的關係,所以可以直接獲取:

上面的 model 中我們定義了 related_name,所以是:

p_1.place_restaurant

如果沒有定義 related_name 和 related_query_name 那麼就是 model 的小寫:

p_1.restaurant

但是從 Place 到 Restaurant 獲取數據,如果沒有這種 OneToOne 的對應,比如我們上面直接創建的 p_1,使用這種方式獲取關聯數據就會報錯,因為沒有這種 OneToOne 的數據。

那麼這個時候我們可以先判斷是否有對應的這種 OneToOne 的數據:

hasattr(p_1, 'place_restaurant')  # 返回的是布爾型數據 

# 或者 
getattr(p_1, 'place_restaurant', None)

以上就是這篇筆記全部內容,接下來將要介紹 model 里的 Meta 的用法。

本文首發於本人微信公眾號:Django筆記。

原文鏈接:Django筆記七之ManyToMany和OneToOne介紹

如果想獲取更多相關文章,可掃碼關註閱讀:
image


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 響應式基本原理就是,在初始化vue實例的時候,對data的每一個屬性都通過 Object.defineProperty 定義一次,在數據被set的時候,做一些操作,改變相應的視圖 ...
  • JavaScript(簡稱“JS”)是當前最流行、應用最廣泛的客戶端腳本語言,用來在網頁中添加一些動態效果與交互功能,在 Web 開發領域有著舉足輕重的地位。JavaScript 與 HTML 和 CSS 共同構成了我們所看到的網頁,其中: HTML 用來定義網頁的內容,例如標題、正文、圖像等; C ...
  • Vue是一款國產前端框架,它的作者尤雨溪(Evan You)是一位美籍華人,2014年2月,尤雨溪開源了一個前端開發庫 Vue.js,2015年發佈1.0.0版本,2016年4月發佈2.0版本,目前,尤雨溪全職投入 Vue.js 的開發與維護,立志將 Vue.js 打造成與 Angular/Reac ...
  • 外觀模式(Facade Pattern):它提供了一個簡單的介面,用於訪問複雜的系統或子系統。通過外觀模式,客戶端可以通過一個簡單的介面來訪問複雜的系統,而無需瞭解系統內部的具體實現細節。 在前端開發中,外觀模式常常被用於封裝一些常用的操作,以簡化代碼複雜度和提高代碼可維護性。比如,一個用於處理數據 ...
  • 最近,在看 LPL 比賽的時候,看到這樣一個有意思的六芒星能力圖動畫: 今天,我們就來使用純 CSS 實現這樣一個動畫效果! 實現背景網格 對於如下這樣一個背景網格,最好的方式當然肯定是切圖,或者使用 SVG 路徑。 如果一定要使用 CSS,勉強也能做,這就涉及了不規則圖形邊框效果,我們有一些方式可 ...
  • title: "modern C++ DesignPattern-Part3" date: 2018-04-12T19:08:49+08:00 lastmod: 2018-04-12T19:08:49+08:00 keywords: [設計模式, C++] tags: [設計模式] categori ...
  • 關於指針、數組、字元串的恩怨,這裡有你想知道的一切 記憶體組成、字元串定義、一/二維數組結構、數組中的指針等價關係、數組結構中對“指針常量”的理解、 指針 vs 數組 記憶體結構一圖流、One More Thing:當二維數組遇見qsort()庫函數,關於比較函數cmp的迷思 ...
  • 模型和基本欄位 在上一章的末尾,我們創建一個odoo模塊。然而,此時它仍然是一個空殼,不允許我們存儲任何數據。在我們的房地產模塊中,我們希望將與房地產相關的信息(名稱(name)、描述(description)、價格(price)、居住面積(living area)…)存儲在資料庫中。odoo框架提 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...