多對一(ForeignKey)
多對一關(guān)系由外鍵實(shí)現(xiàn),外鍵要定義在“多”的一方而账,如:
models.ForeignKey(<主表>, ...)
如果要關(guān)聯(lián)的主表在另一個app中启摄,要顯式的指出:
models.ForeignKey(’<app名稱>.<主表>‘, ...)
?
可創(chuàng)建自己關(guān)聯(lián)自己的外鍵——比如凌外,在評論系統(tǒng)中伴栓,一條評論可被多次引用自身并繼續(xù)評論:
class Comment(models.Model):
????title = models.Charfield(max_length=128)
????text = models.TextField()
????parent_comment = models.ForeignKey(’self’, on_delete=models.CASCADE)
????...
如果在子模型中存在多個外鍵指向同一個主模型,必須給他們加上不同的related_name拳昌,用于反向查詢袭异。
外鍵字段在數(shù)據(jù)庫中的列名是<外鍵名>_id,用來儲存主表對象的id炬藤,因此御铃,在得到主表id的情況下可以不調(diào)用外鍵而直接篩選:
QuerySet = <外鍵表>.filter(<外鍵名>_id=<主表id>)
#獲得與“<主表id>=xxx的主對象”相關(guān)聯(lián)的子對象
多對一的字段參數(shù)
on_delete=models.XXX
當(dāng)主對象被刪除時,關(guān)聯(lián)的子對象的操作(因?yàn)橹麈I不能隨意刪除沈矿,外鍵可以直接刪除)
models.CASCADE:同時刪除關(guān)聯(lián)的子對象上真,Django默認(rèn)
models.PROTECT:阻止CASCADE刪除關(guān)聯(lián)的子對象,并彈出ProtectedError異常
models.SET_NULL:將子對象的外鍵字段設(shè)為null(外鍵字段需設(shè)置null=True)
models.SET_DEFAULT:將子對象的外鍵字段設(shè)為默認(rèn)值(外鍵字段需設(shè)置default=’xxx’)
models.DO_NOTHING:什么也不做
models.SET():設(shè)置為一個傳遞給SET()的值或一個回調(diào)函數(shù)的返回值
注:on_delete是Django2.0之后新增的必選項(xiàng)羹膳。
related_name=’?‘
通過主對象反向引用子對象的通道名稱睡互,默認(rèn)名稱是<小寫子模型名>_set。
如:
class Car(models.Model):
????factory?= models.ForeignKey(
????????Factory, ?????
????????on_delete=models.CASCADE,
????????related_name='car_by_factory',
????)
此時Factory主表取出所有關(guān)聯(lián)的Car對象:factory.car_by_factory.all()
如果不想給外鍵設(shè)置反向關(guān)聯(lián)名稱陵像,就用related_name=’+’或以+號結(jié)尾
related_query_name=’?‘
主對象反向關(guān)聯(lián)查詢的名稱就珠,默認(rèn)查詢名稱是<外鍵列>__<主表的某列>。
如:
class Tag(models.Model):
????article = models.ForeignKey(
????????Article,
????????on_delete=models.CASCADE,
????????related_query_name="tag",
????)
????name = models.CharField(max_length=255)
此時用tag作為查詢名稱:Article.objects.filter(tag__name="A")
limit_choices_to={}
限制外鍵能關(guān)聯(lián)的對象醒颖,用于Django的表單模塊和admin后臺妻怎,可以傳入字典、Q對象泞歉、一個返回字典或Q對象的函數(shù)逼侦。
如:
staff_member = models.ForeignKey(
????User,
????on_delete=models.CASCADE,
????limit_choices_to={'is_staff': True},
)
此時,表單模塊的staff_member字段列表中只會出現(xiàn)is_staff=True的Users對象腰耙,對admin后臺非常有用榛丢。
to_field=’?‘
讓外鍵關(guān)聯(lián)到指定的字段上(默認(rèn)關(guān)聯(lián)到主鍵),該字段必須有unique=True屬性挺庞。
多對一的引用
子對象引用主對象:
<子對象>.<外鍵列>
主對象引用子對象:
<主對象>.<子表小寫>_set
如:
<主對象>.<子表小寫>_set.all() ?????????????????????????#所有關(guān)聯(lián)子對象的集合
<主對象>.<子表小寫>_set.create(<子表字段>=’xxx’, ...) ????#創(chuàng)建關(guān)聯(lián)的子對象
<主對象>.<子表小寫>_set.count() ??????????????????????#查詢關(guān)聯(lián)子對象的數(shù)量
添加多對一關(guān)系:
<子對象>.<外鍵列> = <主對象>
<子對象>.save()
刪除多對一關(guān)系:
<子對象>.<外鍵列> = None ????#外鍵列要設(shè)為null=True
多對一的查詢
查詢子對象的集合:
<子表>.objects.filter(<外鍵列>__<主表的某列>=’xxx’)
#獲得與“<主表的某列>=xxx的主對象”相關(guān)聯(lián)的子對象
查詢主對象的集合:
<主表>.objects.filter(<子表小寫> __<子表的某列>=’xxx’)
#獲得與“<子表的某列>=xxx的子對象”相關(guān)聯(lián)的主對象
多對多(ManyToManyField)
多對多字段可定義在任意一方晰赞,如:
models.ManyToManyField(‘<主表>’)
多對多字段不支持Django內(nèi)置的validators驗(yàn)證功能。
null參數(shù)對ManyToManyField多對多字段無效,設(shè)置null=True毫無意義宾肺。
如果在子模型中存在多個多對多鍵指向同一個主模型溯饵,必須給他們加上不同的related_name侵俗,用于反向查詢锨用。
采用默認(rèn)中間表的數(shù)據(jù)庫結(jié)構(gòu):
<中間表id> ?<多對多表>_id???<主表>_id
默認(rèn)中間表通過保存兩張表的id進(jìn)行關(guān)聯(lián)
采用自定義中間表并添加新字段的數(shù)據(jù)庫結(jié)構(gòu):
<中間表id> ?<新字段1> ?<新字段2> ?<多對多表>_id???<主表>_id
多對多字段的參數(shù)
related_name=’?‘
主對象反向引用多對象時的名稱,和多對一相同隘谣。
related_query_name=’?‘
主對象反向關(guān)聯(lián)查詢的名稱增拥,和多對一相同。
through=’?‘
自定義中間表寻歧,用于保存兩表關(guān)系的附加數(shù)據(jù)掌栅,中間表要有兩個外鍵字段分別指向關(guān)聯(lián)的兩個模型。
through_fields=(<字段1>, <字段2>)
當(dāng)中間表有多個外鍵指向一個表的時候码泛,用through_firlds指定中間表的兩個連接字段猾封,如:
class Person(models.Model):
????name = models.CharField(max_length=32)
class Group(models.Model):
????name = models.CharField(max_length=64)
????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表的外鍵
????????Person,
????????on_delete=models.CASCADE,
????????related_name="membership_invites",
????)
????invite_reason = models.CharField(max_length=128)
db_table=’?‘
設(shè)置中間表的名稱,默認(rèn)為<多對多字段名>_<主表名>_<一串哈希碼>
limit_choices_to={ }
限制多對多鍵關(guān)聯(lián)的對象噪珊,和多對一相同晌缘,對于用through定義中間表的字段無效。
?
多對多的引用
多對象引用主對象:
<多對象>.<多鍵列>
主對象引用多對象:
<主對象>.<多表小寫>_set
添加多對多關(guān)系:(默認(rèn)中間表)
<多對象>.<多鍵列>.add(<主對象>) ????#可同時添加多個主對象
添加多對多關(guān)系:(自定義中間表)
a = <主對象>
b = <多對象>
membership = <中間表>(<主表外鍵列>=a, <多表外鍵列>=b, <字段1>=’xxx’, <字段2>=’xxx’, ...)
membership.save()
#先創(chuàng)建主表和多表的實(shí)例痢站,再創(chuàng)建中間表的連接關(guān)系
#自定義中間表不能用add()磷箕、create()、remove()和set()操作對象的關(guān)系
刪除多對多關(guān)系:
<多對象>.<多鍵列>.clear()
獲取中間表的附加數(shù)據(jù):
a = <主對象>
b = <多對象>
membership = <中間表>.objects.get(<主表外鍵列>=a, <多表外鍵列>=b)
membership.<字段1> ????#獲取字段信息
一對一(OneToOneField)
反向關(guān)聯(lián)的對象只有一個阵难,多數(shù)用于從一個模型擴(kuò)展出另一個模型的情況岳枷。
一對一通過子對象訪問關(guān)聯(lián)的主對象:
<子對象>.<一對一鍵>
一對一通過主對象訪問關(guān)聯(lián)的子對象:
<主對象>.<小寫子模型名>
注意返回的是單個對象而不是集合。