【Django】关联查询set.all() 方法的使用

本文详细介绍了Django中如何使用set.all() 方法进行关联查询,包括通过父表获取子表数据,跨关联关系的查询,以及处理多值关联关系的过滤方式。示例代码展示了在不同场景下如何进行高效查询,帮助理解Django的关联查询机制。
比如说有a b c三张表关系如下 a是b的父表,b是c的父表
a <----- b  <------c
Module  <-----  privilegegroup <----  privilege 

通过父表获取对应的子表的全部

  1. 1.知道具体某个值时
  2. >>> from apps.models import *
  3. >>> b=eproject.objects.get(id=1)
  4. >>> tmp=b.eserver_set.all()
  5. >>> for i in tmp:
  6. ...     print i.host


2.获取多级字表全部
>>> modules = Module.objects.all()
>>> for i in modules:
...     for j in i.privilegegroup_set.all():
...         for k in j.privilege_set.all():
...             print k.privilege_name
... 
用户添加
用户编辑
用户列表
用户状态变更
重置密码
角色添加
角色编辑
角色列表
角色状态变更
模块添加
模块编辑
模块列表
模块状态变更
权限组添加
权限组编辑
权限组列表
权限组状态变更
权限添加
权限编辑
权限列表
权限状态变更
菜单添加
菜单编辑
菜单列表
菜单状态变更
日志列表
日志详情
环境分类
主机列表
添加服务器
机器授权
授权列表
分库分表
慢日志展示

跨关联关系的查询

  1. 原方法:
  2. >>> b=eproject.objects.get(id=2)
  3. >>> for i in b.eserver_set.all():
  4. ... print i.host
  5. ...
  6. 10.4.89.185
  7. 10.32.32.23

跨关联方法:
 >>> for i in eserver.objects.filter(eproject__id='2'):
...    print i.host
... 
10.4.89.185
10.32.32.23


>>> tt=eserver.objects.filter(eproject__id=2)
>>> for i in tt:
...     print i.id,i.eproject.pname
... 
31 ST
32 ST



>>> tt=eserver.objects.all()
>>> for i in tt:
...     print i.id,i.eproject.pname
... 
18 ST1
28 SI
29 SI
30 SI
31 ST
32 ST



  1. from django.db import models

  2. class Blog(models.Model):
  3.     name = models.CharField(max_length=100)
  4.     tagline = models.TextField()

  5.     def __str__(self): # __unicode__ on Python 2
  6.         return self.name

  7. class Author(models.Model):
  8.     name = models.CharField(max_length=50)
  9.     email = models.EmailField()

  10.     def __str__(self): # __unicode__ on Python 2
  11.         return self.name

  12. class Entry(models.Model):
  13.     blog = models.ForeignKey(Blog)
  14.     headline = models.CharField(max_length=255)
  15.     body_text = models.TextField()
  16.     pub_date = models.DateField()
  17.     mod_date = models.DateField()
  18.     authors = models.ManyToManyField(Author)
  19.     n_comments = models.IntegerField()
  20.     n_pingbacks = models.IntegerField()
  21.     rating = models.IntegerField()

  22.     def __str__(self): # __unicode__ on Python 2
  23.         return self.headline

Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:

下面这个例子获取所有Blog 的name 为'Beatles Blog' 的Entry 对象:

>>> Entry.objects.filter(blog__name='Beatles Blog') 

这种跨越可以是任意的深度。

它还可以反向工作。若要引用一个“反向”的关系,只需要使用该模型的小写的名称。

下面的示例获取所有的Blog 对象,它们至少有一个Entry 的headline 包含'Lennon'

>>> Blog.objects.filter(entry__headline__contains='Lennon') 

如果你在多个关联关系直接过滤而且其中某个中介模型没有满足过滤条件的值,Django 将把它当做一个空的(所有的值都为NULL)但是合法的对象。这意味着不会有错误引发。例如,在下面的过滤器中:

Blog.objects.filter(entry__authors__name='Lennon') 

(如果有一个相关联的Author 模型),如果Entry 中没有找到对应的author,那么它将当作其没有name,而不会因为没有author 引发一个错误。通常,这就是你想要的。唯一可能让你困惑的是当你使用isnull 的时候。因此:

Blog.objects.filter(entry__authors__name__isnull=True) 

返回的Blog 对象包括author __name 为空的Blog对象,以及author__name不为空但author__name关联的entry __author 为空的对象。如果你不需要后者,你可以这样写:

Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True) 
跨越多值的关联关系?

当你基于ManyToManyField 或反向的ForeignKey 来过滤一个对象时,有两种不同种类的过滤器。考虑Blog/Entry 关联关系(Blog 和 Entry 是一对多的关系)。我们可能想找出headline为“Lennon” 并且pub_date为'2008'年的Entry。或者我们可能想查询headline为“Lennon” 的Entry或者pub_date为'2008'的Entry。因为实际上有和单个Blog 相关联的多个Entry,所以这两个查询在某些场景下都是有可能并有意义的。

ManyToManyField 有类似的情况。例如,如果Entry 有一个ManyToManyField 叫做 tags,我们可能想找到tag 叫做“music” 和“bands” 的Entry,或者我们想找一个tag 名为“music” 且状态为“public”的Entry。

对于这两种情况,Django 有种一致的方法来处理filter() 调用。一个filter() 调用中的所有参数会同时应用以过滤出满足所有要求的记录。接下来的filter() 调用进一步限制对象集,但是对于多值关系,它们应用到与主模型关联的对象,而不是应用到前一个filter() 调用选择出来的对象。

这些听起来可能有点混乱,所以希望展示一个例子使它变得更清晰。选择所有包含同时满足两个条件的entry的blog,这两个条件是headline 包含Lennon 和发表时间是2008 (同一个entry 满足两个条件),我们的代码是:

Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008) 

从所有的blog模型实例中选择满足以下条件的blog实例:blog的enrty的headline属性值是“Lennon”,或者entry的发表时间是2008(两个条件至少满足一个,也可以同时满足),我们的代码是:

Blog.objects.filter(entry__headline__contains='Lennon').filter( entry__pub_date__year=2008) 

假设这里有一个blog拥有一条包含'Lennon'的entries条目和一条来自2008的entries条目,但是没有一条来自2008并且包含"Lennon"的entries条目。第一个查询不会返回任何blog,第二个查询将会返回一个blog。

在第二个例子中, 第一个filter 限定查询集中的blog 与headline 包含“Lennon” 的entry 关联。第二个filter 又 限定查询集中的blog ,这些blog关联的entry 的发表时间是2008。(译者注:难点在如何理解further这个词!)第二个filter 过滤出来的entry 与第一个filter 过滤出来的entry 可能相同也可能不同。每个filter 语句过滤的是Blog,而不是Entry

跨越多值关系的filter() 查询的行为,与exclude() 实现的不同。单个exclude() 调用中的条件不必引用同一个记录。

例如,下面的查询排除headline 中包含“Lennon”的Entry和在2008 年发布的Entry:

Blog.objects.exclude( entry__headline__contains='Lennon', entry__pub_date__year=2008, ) 

然而,这与使用filter() 的行为不同,它不是排除同时满足两个条件的Entry。为了实现这点,即选择的Blog中不包含在2008年发布且healine 中带有“Lennon” 的Entry,你需要编写两个查询:

Blog.objects.exclude( entry=Entry.objects.filter( headline__contains='Lennon', pub_date__year=2008, ), ) 

具体见官文:

http://python.usyiyi.cn/translate/django_182/topics/db/queries.html






来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29096438/viewspace-2146373/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29096438/viewspace-2146373/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值