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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...