Model关系说明:
UserInfo:员工信息表,Dept:部门,JobLevel:级别
python
1、一对多关系django
一、使用ForeignKey定义,主表被关联的字段,必须是primary_key或unique属性ide
ForeignKey,使用ForeignKey的字段查询时是一个对象,使用.继续查询子表数据函数
主表:to的表,子表,定义ForeignKey的表spa
**注意,若是UserInfo表存在记录,migrate的时候会报错code
1)先把主表录入数据,再在ForeignKey里设置deafultorm
2)把ForeignKey的null设置成True对象
参数 | 说明 | 备注 |
to |
主表名:必填开发 可省略to |
例: 'Group'或to=‘Group’ |
to_feild |
关联主表字段:必须是primarykey或unique 一、省略,自动关联主表的Primarykey 二、指定关联主键字段 三、子表关联字段名自动生成 |
例: s=models.ForeignKey('Salary') 子表自动生成s_id字段 s:定义的ForeignKey名 _id:固定 |
related_name |
给外键定义外部查询方法,替代_set,_set失效 做为方法使用 |
related_name='r' obj.r.filter() |
on_delete |
主表删除数据后,子表作何操做,必填! CASCADE:此值设置,是级联删除。 |
|
default |
外键默认值:若是子表有记录参照下面三条 一、若是不指定,运行makemigrateion出提示 二、先建主表记录,再ForeignKey,不然不符外键约束 三、也可设置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的,会报错!!!!!
二、_set, 主表操做副表记录,须first或get获取单一对象,Queryset列表不能使用_set
level_obj = models.JobLevel.objects.filter(level='SS1').first() # 必须first或get获取单一对象,Queryset列表不能使用_set
2、多对多关系
表结构代码:
一、使用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原理是先删除后创建 # 注意事项: # 一、u2对应中间表多个记录,set把全部对应记录全删掉 # 二、set只建立对应参数的记录 u2.dept_obj.set('3') # 只建立一个对应id为3的记录 u2.dept_obj.set(['2','1']) # 列表前不加*
二、使用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) # 自定义的字段