【Django】關聯查詢set.all() 方法的使用

小亮520cl發表於2017-10-25
比如說有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, ), ) 

具體見官文:








來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29096438/viewspace-2146373/,如需轉載,請註明出處,否則將追究法律責任。

相關文章