溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Django 框架4:ORM高級操作-多表定義與操作

發(fā)布時間:2020-09-06 22:10:03 來源:網(wǎng)絡(luò) 閱讀:509 作者:等你的破船 欄目:編程語言

Model關(guān)系說明:
UserInfo:員工信息表,Dept:部門,JobLevel:級別

Django 框架4:ORM高級操作-多表定義與操作

一、一對多關(guān)系

????1、使用ForeignKey定義,主表被關(guān)聯(lián)的字段,必須是primary_key或unique屬性

????????????ForeignKey,使用ForeignKey的字段查詢時是一個對象,使用.繼續(xù)查詢子表數(shù)據(jù)

????????????主表:to的表,子表,定義ForeignKey的表

????????????**注意,如果UserInfo表存在記錄,migrate的時候會報錯

????????????????1)先把主表錄入數(shù)據(jù),再在ForeignKey里設(shè)置deafult

????????????????2)把ForeignKey的null設(shè)置成True


參數(shù)說明備注
to

主表名:必填

可省略to

例:

'Group'或to=‘Group’

to_feild

關(guān)聯(lián)主表字段:必須是primarykey或unique

1、省略,自動關(guān)聯(lián)主表的Primarykey

2、指定關(guān)聯(lián)主鍵字段

3、子表關(guān)聯(lián)字段名自動生成

例:

s=models.ForeignKey('Salary')

子表自動生成s_id字段

s:定義的ForeignKey名

_id:固定

related_name

給外鍵定義外部查詢方法,替代_set,_set失效

作為方法使用

related_name='r'

obj.r.filter()

on_delete

主表刪除數(shù)據(jù)后,子表做何操作,必填!

CASCADE:此值設(shè)置,是級聯(lián)刪除。
PROTECT:此值設(shè)置,是會報完整性錯誤。
SET_NULL:此值設(shè)置,會把外鍵設(shè)置為null,前提是允許為null。
SET_DEFAULT:此值設(shè)置,會把設(shè)置為外鍵的默認(rèn)值。
SET():此值設(shè)置,會調(diào)用外面的值,可以是一個函數(shù)。


default

外鍵默認(rèn)值:如果子表有記錄參照下面三條

1、如果不指定,運行makemigrateion出提示

2、先建主表記錄,再ForeignKey,否則不符外鍵約束

3、也可設(shè)置null=True設(shè)置為空


related_query_name

給定主表,通過related_query_name查詢副表字段,返回的是主表queryset對象


給外鍵定義外部查詢字段,在filter里使用

副表里定義:related_query_name='r'


Group.objects.fileter(r__name='sa')

返回的是副表name=sa對應(yīng)的Group

limit_choices_to待查
parent_link待查
db_constraint待查

????????表結(jié)構(gòu)代碼

from?django.db?import?models
class?UserInfo(models.Model):
????#?自動生成id,并設(shè)置為主鍵
????name?=?models.CharField(max_length=32)
????age?=?models.SmallIntegerField()
????
????#?定義關(guān)系,只寫模型名,默認(rèn)找JobLevel的primarykey字段
????#?level?=?models.ForeignKey('JobLevel',on_delete=SET_DEFAULT,default='1')
????
????#?to_field可以指定primarykey或unique字段,副表自動生成的依然是level_id字段
????#?level?=?models.ForeignKey('JobLevel',?to_field='id')
????
????level?=?models.ForeignKey('JobLevel',?to_field='id',?related_name='r_method',
???????????????????related_query_name='r_query',?on_delete='SET_NULL',null=true)
????

class?JobLevel(models.Model):
????#?自動生成id,并設(shè)置為主鍵
????name?=?CharField(max_lengh=32)
????salary?=?IntegerField()
????
????
#?添加:level可以賦對象值。
models.UserInfo.objects.create(username='root4',password=1111,
???????????????????????????????level=models.JobLevel.objects.filter(level='SS1').first()
???????????????????????????????)

????????查詢:

????????????_set,主表操作副表記錄,須first或get獲取單一對象,Queryset列表不能使用_set

#?-副表->主表
u=models.UserInfo.objects.filter(id=1).first()????????#?使用filter的結(jié)果是queryset對象,所以加first只取一個Models對象,方便操作。
u.level???????????????????????????????????????????????#?.定義的外鍵名,結(jié)果是JobLevel對象
u.level.salary????????????????????????????????????????#?.定義的外鍵名.主表字段,結(jié)果是查詢主表的對應(yīng)字段值?
#?使用雙下劃線__查詢:
u=models.UserInfo.objects.filter(level__salary=10000)?#?通過外鍵level__salary,查詢工資是10000的所有用戶

????
#?-通過主表查副表:
????#使用related_name查詢
s=j.r_method.all()????????????????????????????????????#?通過related_name查詢,結(jié)果是queryset類型
????#使用_set,需要把ForeignKey里面的related_name刪掉。否則報錯。
s=j.userinfo_set.all()????????????????????????????????#?結(jié)果和上面一樣
????#使用related_query_name查詢
s=models.JobLevel.objects.filter(r_query__name='root')????#?root對應(yīng)的joblevel,返回的是QuerySet對象
????
#?-通過副表__查詢主表:
s=models.UserInfo.objects.filter(joblevel__name='s1')?????#?查詢S1職位對應(yīng)的所有用戶。

????修改

????????update基于字段修改

????????add基于對象更改,自動找到關(guān)聯(lián)外鍵字段

????????對于ForeignKey對象,clear()和remove()方法僅在null=True時存在。

????????一對多,對于.remove和.add只能在_set情況下使用,通過主表改副表里用,remove:清空字段,字段必須null=True

#?修改1:使用queryset對象更新副表
j=models.JobLevel.objects.filter(id=2).first()
u=models.UserInfo.objects.filter(id__lt=10)???????????#?注意獲取到的是queryset對象
u.update(level=j)?????????????????????????????????????#?因為level字段是一個對象,所以把查詢到的對象j賦值給level
#?修改2:使用obj更新副表
for?u_obj?in?u:???????????????????????????????????????#?直接給UserInfo表賦值
????u_obj.update(level_id=j.id)
????#?或:u_obj.update(level_id=2)

#?修改3:使用_set修改,通過主表對象修改副表
j.userinfo_set.add(*u)????????????????????????????????#?使用*u把對象j傳給QuerySet對象
j.userinfo_set.add(obj_u)?????????????????????????????#?把j傳遞給obj_u的models對象。

????刪除:

????????是指刪除副表關(guān)聯(lián)字段的值

#?j.userinfo_set.remove(*u)
#?這個是坑,*u里的所有對象必須都關(guān)聯(lián)id=2的對象,如果有關(guān)聯(lián)id=3的,會報錯?。。。?!

??????????

????2、_set,???主表操作副表記錄,須first或get獲取單一對象,Queryset列表不能使用_set

level_obj?=?models.JobLevel.objects.filter(level='SS1').first()????#?必須first或get獲取單一對象,Queryset列表不能使用_set


二、多對多關(guān)系

????表結(jié)構(gòu)代碼:

????????1、使用ManyToManyField自動生成中間表結(jié)構(gòu)

????????????優(yōu)點:表自動維護(hù),缺點:無法直接對表進(jìn)行操作。

????????默認(rèn)中間表名:應(yīng)用_表1_表1定義的外鍵名,例:ormtest_userinfo_dept_obj

class?UserInfo(models.Model):
????#?自動生成id,并設(shè)置為主鍵
????name?=?models.CharField(max_length=32)
????age?=?models.SmallIntegerField()??????
????level?=?models.ForeignKey('JobLevel',?to_field='id',?related_name='r_method',
???????????????????related_query_name='r_query',?on_delete='SET_NULL',null=true)
????dept_obj?=?models.ManyToManyField('Dept')
????
class?Dept(models.Model):
????name?=?models.CharField(max_length=50)
????code?=?models.CharField(max_length=50,?unique=True)

????????操作:

"""ManyToManyField"""
#?創(chuàng)建Dept表記錄
models.Dept.objects.create(name='開發(fā)部',code='KF0001')
models.Dept.objects.create(name='總務(wù)部',code='ZW0002')
models.Dept.objects.create(name='采購部',code='CG0003')

#?添加1,通過對象,add添加
u1?=?models.UserInfo.objects.filter(name='root').first()
d1?=?models.Dept.objects.filter(name='開發(fā)部').first()
u1.dept_obj.add(d1)

#?添加1-2,通過對象,添加多個
u1?=?models.UserInfo.objects.filter(name='user')
d1?=?models.Dept.objects.filter(name='開發(fā)部').first()
d1.userinfo_set.add(*u1)????????#?把u1所有的對象都和d1建立關(guān)聯(lián)

#?添加2,通過id,add添加
u1?=?models.UserInfo.objects.filter(name='root1').first()
u1.dept_obj.add(*[1,?3])??????#?添加多個
u1.dept_obj.add(2)????????#?添加一個
#?添加3,通過對象,使用_set?返向add添加
u1?=?models.UserInfo.objects.filter(name='root').first()
d1?=?models.Dept.objects.filter(name='開發(fā)部').first()
d1.userinfo_set.add(u1)

#?查詢1,使用__查副表字段:
u3?=?models.UserInfo.objects.filter(dept_obj__name='開發(fā)部').all()
#?查詢2,使用_set查詢
d3?=?models.Dept.objects.filter(name='開發(fā)部').first()
u3?=?d3.userinfo_set????????????????????#?與查詢1的u3一樣


#?刪除1,移除field值,從中間表刪除整條記錄
u2?=?models.UserInfo.objects.filter(name='root').first()
d2?=?models.Dept.objects.filter(name='總務(wù)部').first()
d2.userinfo_set.remove(u2)

#?刪除2,清空對應(yīng)的中間表記錄
d2.userinfo_set.clear()

#?使用.set修改關(guān)聯(lián)值:通過中間表ID可以判斷出來,set原理是先刪除后建立
#?注意事項:
????#?1、u2對應(yīng)中間表多個記錄,set把所有對應(yīng)記錄全刪掉
????#?2、set只創(chuàng)建對應(yīng)參數(shù)的記錄
u2.dept_obj.set('3')????????#?只創(chuàng)建一個對應(yīng)id為3的記錄
u2.dept_obj.set(['2','1'])??#?列表前不加*

????????2、使用Foreignkey實現(xiàn)多表關(guān)聯(lián)

????????????優(yōu)點:可以自定義中間表結(jié)構(gòu)。

class?UserInfo(models.Model):
????#?自動生成id,并設(shè)置為主鍵
????name?=?models.CharField(max_length=32)
????age?=?models.SmallIntegerField()??????
????department?=?models.ManyToManyField
????dept_obj?=?models.ManyToManyField('Dept')


class?Dept(models.Model):
????name?=?models.CharField(max_length=50)
????code?=?models.CharField(max_length=50,?unique=True)

class?UserInfo_To_Dept(models.Model):
????userinfo?=?models.ForeignKey('UserInfo')
????dept?=?models.ForeignKey('Dept')
????level?=?models.CharField(max_length=50)????????#?自定義的字段




向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI