您好,登錄后才能下訂單哦!
小編給大家分享一下基于Django的OneToOneField和ForeignKey有哪些區別,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
根據Django官方文檔介紹:
A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.
OneToOneField與ForeignKey加上unique=True效果基本一樣,但是用OneToOneField反向關聯會直接返回對象。
相反地,使用ForeignKey, 反向關聯后會返回QuerySet。
例子:
from django.db import models class Engine(models.Model): name = models.CharField(max_length=25) def __unicode__(self): return self.name class Car(models.Model): name = models.CharField(max_length=25) engine = models.OneToOneField(Engine) def __unicode__(self): return self.name class Engine2(models.Model): name = models.CharField(max_length=25) def __unicode__(self): return self.name class Car2(models.Model): name = models.CharField(max_length=25) engine = models.ForeignKey(Engine2, unique=True) def __unicode__(self): return self.name
在python manage.py shell里輸入:
>>> from testapp.models import Car, Engine >>> c = Car.objects.get(name='Audi') >>> e = Engine.objects.get(name='Diesel') >>> e.car # OneToOneField的反向關聯屬性如果沒有寫relate_name, 則是對方類名的小寫 <Car: Audi>
>>> from testapp.models import Car2, Engine2 >>> c2 = Car2.objects.get(name='Mazda') >>> e2 = Engine2.objects.get(name='Wankel') >>> e2.car2_set.all() # OneToOneField的反向關聯屬性如果沒有寫relate_name, 則是對方類名的小寫_set [<Car2: Mazda>]
補充知識:Django ForeignKey,ManyToManyField和OneToOneField的辨析
導引
模型(Models)是對網站所需信息種類的定義,其包含了網站存儲數據中的重要字段和數據行為。一般來說,一個模型對于數據庫中的一個表單。
字段(Fields)是模型的重要和唯一組成部分,他們由類別的屬性值所指定。
Field分類
由官方文檔Model field reference | Django Documentation定義:
Field一共分為AutoField、BinaryField、BooleanField、CharField、DateField、DecimalField、EmailField、FileField、FloatField、IntegerField、TextField、TimeField、URLField等類別,豐富的類別選項為數據庫存儲方式提供了完善的支持,而本文主要是針對如下三個關系型字段(Relationship fields):
關系型字段 | 對應關系 |
---|---|
ForeignKey | 多對一 |
ManyToManyField | 多對多 |
OneToOneField | 一對一 |
分析
ForeignKey
首先查看源碼,在類的開頭有如下參數:
many_to_many = False
many_to_one = True
one_to_many = False
one_to_one = False
由此可見,ForeignKey是many_to_one類型的,即“一對多”,我們引用官方文檔給出的示例:
from django.db import models class Car(models.Model): manufacturer = models.ForeignKey( 'Manufacturer', on_delete=models.CASCADE, ) # ... class Manufacturer(models.Model): # ... pass
由此我們可以看到,Car類型中有manufacturer字段,其類型是對應Manufacturer類的ForeignKey。我們可以根據生活常識理解這種定義,由于一部汽車對應一個生產商,而一個生產商可以對應許多部汽車,所以兩者具有“一對多”的關系,在此種情況我們使用ForeignKey。
對于每個ForeignKey,我們需要給出關聯的模型和on_delete響應的選項,即
manufacturer = models.ForeignKey( 'Manufacturer', on_delete=models.CASCADE, )
on_delete函數的作用是在此字段被刪除的時候做出的響應,其可選項如下:
選項 | 功能 |
---|---|
CASCADE | 級聯刪除,此類選項模仿SQL語句ON DELETE CASCADE,再刪除此字段信息的時候同時刪除包含ForeignKey字段的目標(object) |
PROTECT | 通過django.db.IntegrityError中的ProtectedError來保護此字段不被刪除,若進行刪除操作則拋出錯誤 |
SET_NULL | 將ForeignKey置為空,這只在null選項為True的時候產生作用 |
SET_DEFAULT | 設為默認值(default value),此默認值已預先對ForeignKey設置 |
SET() | 對ForeignKey設置對SET()函數傳遞的數值 |
DO_NOTHING | 不進行任何操作。若數據庫提高了引用完整性,則此種設置會拋出一個IntegrityError,除非對這一數據字段手動添加了SQL語句中的ON DELETE字段 |
還可以通過設置abstract屬性來定義一個抽象類:
from django.db import models class AbstractCar(models.Model): manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE) class Meta: abstract = True
ForeignKey還有如下的參數可以選擇:
參數 | 功能 |
---|---|
limit_choices_to | 通過一個限制對字段信息的某一可能選項進行約束,可以通過字典,函數或者查詢值來設置 |
related_name | 可以指定關聯的類在本類中的名稱,通過這一參數可以用兩個字段名引用同一個類,通過這個名稱父類可以取得子類的值,默認為字段名 |
related_query_name | 用于filter函數過濾和values函數 |
to_field | 關系關聯的相關對象名稱 |
db_constraint | 控制在數據庫中是否應該建立這一字段的約束 |
swappable | 用于控制這一字段對于可交換類模型的行為 |
ManyToManyField
同樣在源碼中我們可以找到針對ManyToManyField的如下定義:
many_to_many = True
many_to_one = False
one_to_many = False
one_to_one = False
由此可以知道,ManyToManyField是針對“many-to-many”即多對多關系定義的,它需要知道它關聯的類別。
官方文檔給出的示例代碼可以幫助理解:
from django.db import models class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
在示例代碼中,Pizza類的toppings字段由ManyToManyField與Toppings關聯,我們可以由生活常識得出一片披薩上面會有很多種類的佐料,而一種佐料又可以用來制作多種披薩,兩者滿足“多對多”的關系。
ManyToManyField類有兩個經常使用的參數:through和through_fields,通過這兩個參數可以十分方便地建立中間項的關聯,如示例代碼所示:
from django.db import models 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)
在Group類中有ManyToManyField類的字段members,這一字段通過through參數與membership聯系起來,后者表示“成員資格”,即表示“團體”與“個人”之間關系的中間項,而“through_fields”字段即為中間項連接起來的兩個類名,此處即group和person兩個類。
ManyToManyField還有以下參數可以選擇:
參數 | 功能 |
---|---|
related_name | 同ForeignKey,可以指定關聯的類在本類中的名稱 |
related_query_name | 同ForeignKey,應用于filter和values函數 |
limit_choices_to | 同ForeignKey,但如果自己定義了如“Membership”之類的中間類,則不會起到作用 |
symmetrical | 對于迭代定義的ManyToManyField,其為這一字段建立一個單獨的屬性,而是設定symmetrical屬性為True,若期望使用此類迭代關系,可以手動設置其為False |
through | 如上所示,用于設置中間項的名字,可以自己定義一個中間項,若不定義的話系統也會分配一個中間項 |
through_fields | 通過元組來給出中間項關聯的兩個類名,可以查看上面的示例 |
db_table | 可以通過這一屬性來手動設定保存這一字段的數據表名稱,若不設置則默認為字段的名稱 |
db_contraint | 是否在數據庫中建立約束 |
swappable | 設置是否指向一個可交換的模型 |
OneToOneField
源碼中對OneToOneField的設置如下:
many_to_many = False
many_to_one = False
one_to_many = False
one_to_one = True
可知其是針對單對單的關系設定的字段。在概念上我們可以理解其為設置unique屬性為True的一種類型,區別之處在于它“反向”的數值會返回一個目標值,這對于繼承關系的表達十分有用,例如一下示例程序:
from django.conf import settings from django.db import models class MySpecialUser(models.Model): user = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, ) supervisor = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='supervisor_of', )
OneToOneField既包含ForeignKey中的參數,又包含一個額外的參數parent_link,若定義了一個類,其繼承了一個非抽象的類,而設置parent_link這個函數為True,則會將這個類視作繼承的類的父類,而不是一個新的OneToOneField。
看完了這篇文章,相信你對“基于Django的OneToOneField和ForeignKey有哪些區別”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。