Model關係說明:
UserInfo:員工信息表,Dept:部門,JobLevel:級別
一、一對多關係
1、使用ForeignKey定義,主表被關聯的字段,必須是primary_key或unique屬性
ForeignKey,使用ForeignKey的字段查詢時是一個對象,使用.繼續查詢子表數據
主表:to的表,子表,定義ForeignKey的表
**注意,如果UserInfo表存在記錄,migrate的時候會報錯
1)先把主表錄入數據,再在ForeignKey裏設置deafult
2)把ForeignKey的null設置成True
參數 | 說明 | 備註 |
to | 主表名:必填 可省略to | 例: 'Group'或to=‘Group’ |
to_feild | 關聯主表字段:必須是primarykey或unique 1、省略,自動關聯主表的Primarykey 2、指定關聯主鍵字段 3、子表關聯字段名自動生成 | 例: s=models.ForeignKey('Salary') 子表自動生成s_id字段 s:定義的ForeignKey名 _id:固定 |
related_name | 給外鍵定義外部查詢方法,替代_set,_set失效 作爲方法使用 | related_name='r' obj.r.filter() |
on_delete | 主表刪除數據後,子表做何操作,必填! CASCADE:此值設置,是級聯刪除。 | |
default | 外鍵默認值:如果子表有記錄參照下面三條 1、如果不指定,運行makemigrateion出提示 2、先建主表記錄,再ForeignKey,否則不符外鍵約束 3、也可設置null=True設置爲空 | |
related_query_name | 給定主表,通過related_query_name查詢副表字段,返回的是主表queryset對象 給外鍵定義外部查詢字段,在filter裏使用 | 副表裏定義:related_query_name='r' Group.objects.fileter(r__name='sa') 返回的是副表name=sa對應的Group |
limit_choices_to | 待查 | |
parent_link | 待查 | |
db_constraint | 待查 |
表結構代碼
from django.db import models class UserInfo(models.Model): # 自動生成id,並設置爲主鍵 name = models.CharField(max_length=32) age = models.SmallIntegerField() # 定義關係,只寫模型名,默認找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,並設置爲主鍵 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的結果是queryset對象,所以加first只取一個Models對象,方便操作。 u.level # .定義的外鍵名,結果是JobLevel對象 u.level.salary # .定義的外鍵名.主表字段,結果是查詢主表的對應字段值 # 使用雙下劃線__查詢: u=models.UserInfo.objects.filter(level__salary=10000) # 通過外鍵level__salary,查詢工資是10000的所有用戶 # -通過主表查副表: #使用related_name查詢 s=j.r_method.all() # 通過related_name查詢,結果是queryset類型 #使用_set,需要把ForeignKey裏面的related_name刪掉。否則報錯。 s=j.userinfo_set.all() # 結果和上面一樣 #使用related_query_name查詢 s=models.JobLevel.objects.filter(r_query__name='root') # root對應的joblevel,返回的是QuerySet對象 # -通過副表__查詢主表: s=models.UserInfo.objects.filter(joblevel__name='s1') # 查詢S1職位對應的所有用戶。
修改
update基於字段修改
add基於對象更改,自動找到關聯外鍵字段
對於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對象。
刪除:
是指刪除副表關聯字段的值
# j.userinfo_set.remove(*u) # 這個是坑,*u裏的所有對象必須都關聯id=2的對象,如果有關聯id=3的,會報錯!!!!!
2、_set, 主表操作副表記錄,須first或get獲取單一對象,Queryset列表不能使用_set
level_obj = models.JobLevel.objects.filter(level='SS1').first() # 必須first或get獲取單一對象,Queryset列表不能使用_set
二、多對多關係
表結構代碼:
1、使用ManyToManyField自動生成中間表結構
優點:表自動維護,缺點:無法直接對錶進行操作。
默認中間表名:應用_表1_表1定義的外鍵名,例:ormtest_userinfo_dept_obj
class UserInfo(models.Model): # 自動生成id,並設置爲主鍵 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""" # 創建Dept表記錄 models.Dept.objects.create(name='開發部',code='KF0001') models.Dept.objects.create(name='總務部',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='開發部').first() u1.dept_obj.add(d1) # 添加1-2,通過對象,添加多個 u1 = models.UserInfo.objects.filter(name='user') d1 = models.Dept.objects.filter(name='開發部').first() d1.userinfo_set.add(*u1) # 把u1所有的對象都和d1建立關聯 # 添加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='開發部').first() d1.userinfo_set.add(u1) # 查詢1,使用__查副表字段: u3 = models.UserInfo.objects.filter(dept_obj__name='開發部').all() # 查詢2,使用_set查詢 d3 = models.Dept.objects.filter(name='開發部').first() u3 = d3.userinfo_set # 與查詢1的u3一樣 # 刪除1,移除field值,從中間表刪除整條記錄 u2 = models.UserInfo.objects.filter(name='root').first() d2 = models.Dept.objects.filter(name='總務部').first() d2.userinfo_set.remove(u2) # 刪除2,清空對應的中間表記錄 d2.userinfo_set.clear() # 使用.set修改關聯值:通過中間表ID可以判斷出來,set原理是先刪除後建立 # 注意事項: # 1、u2對應中間表多個記錄,set把所有對應記錄全刪掉 # 2、set只創建對應參數的記錄 u2.dept_obj.set('3') # 只創建一個對應id爲3的記錄 u2.dept_obj.set(['2','1']) # 列表前不加*
2、使用Foreignkey實現多表關聯
優點:可以自定義中間表結構。
class UserInfo(models.Model): # 自動生成id,並設置爲主鍵 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) # 自定義的字段