一个模糊的问题,梳理清楚

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) 
用户组ug1中的用户

数据库确认:


用户组ug1中的用户
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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容