該工程為在保存時執行開發的功能,函數入口點ufput。其他還有新建、打開、另存等都可以加入開發的操作,具體看UF_EXIT下的介紹。 用戶出口是一個可選特性,允許你在NX中某些預定義的位置(或出口)自動運行Open C API程式。如果你進入其中一個出口,NX會檢查你是否定義了指向Open C AP ...
ManyToMany 是一種多對多的關係,在用途和使用方法上和外鍵 ForeignKey 類似。
以下是本篇筆記的目錄:
- ManyToMany 的介紹
- through 參數
- through_fields 參數
- ManyToMany關係數據的增刪改查
- 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介紹
如果想獲取更多相關文章,可掃碼關註閱讀: