django模型中一对多与多对多关系梳理,三天时间慢慢梳理完。
一对多关系即是数据库中外键约束。
多对多关系既是数据库中两个表关联形成多对多关系(通过中间表,将在此表中设置两个外键字段分别为另外两张表的主键)。
问题:
1、如何在django模型中建立此类关联关系?又是如何反应到实际数据库中?
2、在视图中如何利用模型类操作数据库?
3、在关联关系中,如何更新数据库?(多对多关系)
4、在关联关系中,如何查询数据库?(多对多关系)
5、在关联关系中,如何进行多级关系深度查询?(一对多,多对多分开讲)
1,2问题比较简单,直接上代码:
1、问题解答:
# 主机表
class Host(models.Model):
id = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=50)
lanip = models.GenericIPAddressField()
class Meta:
managed = True
db_table = 'host'
# 主机组表
class HostGroup(models.Model):
hgid = models.AutoField(primary_key=True)
hgname = models.CharField(max_length=50)
hginfo = models.CharField(max_length=200,default='null')
hosts = models.ManyToManyField(Host)
class Meta:
managed = True
db_table = 'hostgroup'
# 用户组表
class UserGroup(models.Model):
gid = models.AutoField(primary_key=True)
groupname = models.CharField(max_length=50)
ginfo = models.CharField(max_length=200,default='null')
userpri = models.BooleanField(default=False,null=False)
grouppri = models.BooleanField(default=False,null=False)
hgrouppri = models.BooleanField(default=False,null=False)
hostgroups = models.ManyToManyField(HostGroup)
class Meta:
managed = True
db_table = 'usergroup'
# 角色表
class Role(models.Model):
name = models.CharField(max_length=10)
class Meta:
managed = True
db_table = 'role'
# 用户表
class User(models.Model):
uid = models.AutoField(primary_key=True)
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
user = models.CharField(max_length=50)
role = models.ForeignKey(Role,default=1)
groups = models.ManyToManyField(UserGroup)
class Meta:
managed = True
db_table = 'user'
# 解释:
# Role与User表建立一对多关联关系
# 其他表之间建立多对多关联关系,比如User与UserGroup表之间,是在User类中定义一个名字为groups的类属性,利用ManyToManyField多对多关系关联两表,此类型字段只需要在两张表中任意一张表定义即可,无需两张表都定义,模型的管理器会自动在数据库中建立中间表来实现。
# 数据库中,表情况:
2、问题解答:(访问test接口测试更新数据)
1、利用模型对象更新数据(无外键):
def test(request):
for i in xrange(1,4):
rl = Role()
rl.name = "role" + str(i)
rl.save()
return HttpResponse("data")
# 往role表中插入数据,定义Role对象,字段,对象调去save()方法即可,模型管理器会自动识别你是否在此类中定义主键,如果没有会自动添加id字段为主键,自增长。
2、利用模型对象更新数据(有外键):
def test(request):
# for i in xrange(1,4):
# rl = Role()
# rl.name = "role" + str(i)
# rl.save()
for i in xrange(1,15):
if i <= 3:
rl = Role.objects.get(pk=1)
us = User()
us.username = 'admin' + str(i)
us.password = 'admin' + str(i)
us.user = 'neo' + str(i)
us.role = rl
us.save()
elif 3 < i <= 7:
rl = Role.objects.get(pk=2)
us = User()
us.username = 'admin' + str(i)
us.password = 'admin' + str(i)
us.user = 'neo' + str(i)
us.role = rl
us.save()
elif 7 < i <= 10:
rl = Role.objects.get(pk=3)
us = User()
us.username = 'admin' + str(i)
us.password = 'admin' + str(i)
us.user = 'neo' + str(i)
us.role = rl
us.save()
# 利用模型类对象更新具有外键约束表时,需要先创建外键约束对应对象,接在在更新到表中,否则会失败。
3、问题解答:(一对多关系是外键约束更新数据上面既是)
关联管理器在一对多,多对多的关联上下文中使用的管理器:
ForeignKey关系:(一对多关系)
class Role(models.Model):
# ...
pass
class User(models.Model):
role = models.ForeignKey(Role)
# 这样,管理器可以使用role.user_set方法。
ManyToMany关系:(多对多关系)
class UserGroup(models.Model):
# ...
pass
class User(models.Model):
groups = models.ManyToManyField(UserGroup)
# 这样,管理器可以使用usergroup.user_set和user.groups方法。
多对多关联关系更新数据:先将host,hostgroup,usergroup数据填充上。
# 填充host数据
for i in xrange(1,10):
ser = Host()
ser.hostname = "hostname" + str(i)
ser.lanip = "10.10.10." + str(i)
ser.save()
# 填充hostgroup数据
for i in xrange(1,5):
hg = HostGroup()
hg.hgname = "hg" + str(i)
hg.hginfo = "hginfo" + str(i)
hg.save()
# 填充usergroup数据
for i in xrange(1,5):
ug = UserGroup()
ug.groupname = 'ugname' + str(i)
ug.save()
多对多关联关系更新数据:
比如User与UserGroup表之间的多对多关系。
# 获取用户组对象
ug1 = UserGroup.objects.get(pk=1)
ug2 = UserGroup.objects.get(pk=2)
ug3 = UserGroup.objects.get(pk=3)
ug4 = UserGroup.objects.get(pk=4)
# 获取用户对象
u1 = User.objects.get(pk=1)
u2 = User.objects.get(pk=2)
u3 = User.objects.get(pk=3)
u4 = User.objects.get(pk=4)
u5 = User.objects.get(pk=5)
u6 = User.objects.get(pk=6)
u7 = User.objects.get(pk=7)
u8 = User.objects.get(pk=8)
u9 = User.objects.get(pk=9)
u10 = User.objects.get(pk=10)
# 多对多关系数据更新:
# 例一:将ug1用户组关联u1~u3这个三个用户。
ug1.user_set.add(u1,u2,u3) # 利用user_set方法
数据库表展示:
# 反之例二:将u4这个用户,关联到ug2,ug3,ug4这三个用户组中。
u4.groups.add(ug2,ug3,ug4) # 利用groups这个类属性
数据库表展示:
# 例三:移除关联对象的关联关系
# 将用户id 4的用户从用户组4中移除
ug4.user_set.remove(u4) # 从ug4角度移除
u4.groups.remove(ug4) # 从u4角度移除
# 两种方式效果一样
# 数据库展示:
4、问题解答:多对多关联关系查询
# 例:查找用户组ug1中,关联的所有用户组
ug1 = UserGroup.objects.get(pk=1)
users = ug1.user_set.all()
lu = []
for u in users:
lu.append(u.user)
return HttpResponse(lu)
数据库确认:
5、问题解答:多级关联关系查询
建立用户组,主机组,主机表关联关系。
h1 = Host.objects.get(pk=1)
h2 = Host.objects.get(pk=2)
h3 = Host.objects.get(pk=3)
h4 = Host.objects.get(pk=4)
h5 = Host.objects.get(pk=5)
h6 = Host.objects.get(pk=6)
h7 = Host.objects.get(pk=7)
h8 = Host.objects.get(pk=8)
hg1 = HostGroup.objects.get(pk=1)
hg2 = HostGroup.objects.get(pk=2)
ug1 = UserGroup.objects.get(pk=1)
ug1.hostgroups.add(hg1,hg2)
hg1.hosts.add(h1,h2,h3,h4)
hg2.hosts.add(h5,h6,h7,h8)
return HttpResponse("hehe")
# 主机h1~h4关联到hg1中,h5~h8关联到hg2中。
# 用户组ug1 关联hg1与hg2两个主机组
数据库展示
例一:查询role id 为1 的所有用户的,所有用户组的,所有主机组的,所有主机。也就是从role表,查到host表。
hostset = Host.objects.filter(hostgroup__usergroup__user__role=1)
host = []
for i in hostset:
host.append(i.hostname)
host.append('\n')
return HttpResponse(host)
查询结果:
role id 为1的用户有admin1,admin2,admin3,所属的组是usergroup1,关联的主机组有hostgroup1,hostgroup2,其中hostgroup1中有主机hostname1,2,3,4 另外hostgroup2中有主机hostname5,6,7,8,所以查询结果是正确。
例二:查询host id 为1 的主机,所属的关联用户,也就是从host表,查到user表。
users = User.objects.filter(groups__hostgroups__hosts=1)
user = []
for i in users:
user.append(i.user)
user.append('\n')
return HttpResponse(user)
# 查询结果:
# 以上两例子是从不同方向使用关联对象查询,注意:user.groups与usergroup.user_set方法的使用。
总结:
1、django中模型通过模型管理器objects(默认,可以重写),操作数据库。
2、模型使得数据库操作对象抽象为python语言的类对象,并且将一对多关系与多对多关系,抽象成为两个对象之间的关联关系。
3、利用模型封装好的user.groups与usergroup.user_set方法,来实现多对多关系的操作,具体操作方法有(add(),remove(),create(),clear())
4、操作关联对象关系的深度是无限制的,只要两个对象之间至少存在一条关联关系链即可,相互查询。
自己提问自己,自己解答问题。
参考官方文档:
https://docs.djangoproject.com/en/1.11/
https://docs.djangoproject.com/en/1.11/ref/models/instances/
https://docs.djangoproject.com/en/1.11/ref/models/relations/