Django中Q查詢及Q()對象


 

問題

一般我們在Django程序中查詢數據庫操作都是在QuerySet里進行進行,例如下面代碼:

>>> q1 = Entry.objects.filter(headline__startswith="What") >>> q2 = q1.exclude(pub_date__gte=datetime.date.today()) >>> q3 = q1.filter(pub_date__gte=datetime.date.today())   

或者將其組合起來,例如:

>>>q1 = Entry.objects.filter(headline_startswith="What").exclude(pub_date_gte=datetime.date.today())
 

隨着我們的程序越來越復雜,查詢的條件也跟着復雜起來,這樣簡單的通過一個filter()來進行查詢的條件將導致我們的查詢越來越長。

 

 

Q()對象就是為了將這些條件組合起來。

當我們在查詢的條件中需要組合條件時(例如兩個條件“且”或者“或”)時。我們可以使用Q()查詢對象。例如下面的代碼

fromdjango.db.modelsimports Q
q=Q(question_startswith="What")
 

這樣就生成了一個Q()對象,我們可以使用符號&或者|將多個Q()對象組合起來傳遞給filter(),exclude(),get()等函數當多個Q()對象組合起來時,Django會自動生成一個新的Q()。例如下面代碼就將兩個條件組合成了一個

Q(question__startswith='Who') | Q(question__startswith='What')
 

使用上述代碼可以使用SQL語句這么理解:

WHEREquestionLIKE 'Who%' ORquestionLIKE 'What%'
 

我們可以在Q()對象的前面使用字符“~”來代表意義“非”,例如下面代碼:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)
 

對應SQL語句可以理解為:

WHEREquestionlike "Who%" ORyear(pub_date) !=2005   

這樣我們可以使用 “&”或者“|”還有括號來對條件進行分組從而組合成更加復雜的查詢邏輯。

也可以傳遞多個Q()對象給查詢函數,例如下面代碼:

News.objects.get(
    Q(question__startswith='Who'),     Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) )   

多個Q()對象之間的關系Django會自動理解成“且(and)”關系。如上面代碼使用SQL語句理解將會是:

SELECT * fromnewsWHEREquestionLIKE 'Who%'  AND (pub_date = '2005-05-02' ORpub_date = '2005-05-06')   

Q()對象可以結合關鍵字參數一起傳遞給查詢函數,不過需要注意的是要將Q()對象放在關鍵字參數的前面,看下面代碼

#正確的做法
News.objects.get(     Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),     question__startswith='Who')   #錯誤的做法,代碼將關鍵字參數放在了Q()對象的前面。 News.objects.get(     question__startswith='Who',     Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))  

 

使用Q 對象進行復雜的查詢

filter() 等方法中的關鍵字參數查詢都是一起進行“AND” 的。 如果你需要執行更復雜的查詢(例如OR 語句),你可以使用Q 對象

Q 對象 (django.db.models.Q) 對象用於封裝一組關鍵字參數。這些關鍵字參數就是上文“字段查詢” 中所提及的那些。

例如,下面的Q 對象封裝一個LIKE 查詢:

from django.db.models import Q
Q(question__startswith='What')

Q 對象可以使用&| 操作符組合起來。當一個操作符在兩個Q 對象上使用時,它產生一個新的Q 對象。

例如,下面的語句產生一個Q 對象,表示兩個"question__startswith" 查詢的“OR” :

Q(question__startswith='Who') | Q(question__startswith='What')

它等同於下面的SQL WHERE 子句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

你可以組合&|  操作符以及使用括號進行分組來編寫任意復雜的Q 對象。同時,Q 對象可以使用~ 操作符取反,這允許組合正常的查詢和取反(NOT) 查詢:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

每個接受關鍵字參數的查詢函數(例如filter()exclude()get())都可以傳遞一個或多個Q 對象作為位置(不帶名的)參數。如果一個查詢函數有多個Q 對象參數,這些參數的邏輯關系為“AND"。例如:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

... 大體上可以翻譯成這個SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

查詢函數可以混合使用Q 對象和關鍵字參數。所有提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND”在一起。但是,如果出現Q 對象,它必須位於所有關鍵字參數的前面。例如:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

... 是一個合法的查詢,等同於前面的例子;但是:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

... 是不合法的。

另見

Django 單元測試中的OR 查詢示例演示了幾種Q 的用法。

Django的Q對象實現的源碼中:

 

 

[python]  view plain  copy
 
  1. # 位於/django/db/models/query_utils.py  
  2.   
  3. class Q(tree.Node):  
  4.     """ 
  5.     Encapsulates filters as objects that can then be combined logically (using 
  6.     & and |). 
  7.     """  
  8.     # Connection types  
  9.     AND = 'AND'  
  10.     OR = 'OR'  
  11.     default = AND  
  12.   
  13.     def __init__(self, *args, **kwargs):  
  14.         super(Q, self).__init__(children=list(args) + kwargs.items())  
  15.   
  16.     def _combine(self, other, conn):  
  17.         if not isinstance(other, Q):  
  18.             raise TypeError(other)  
  19.         obj = type(self)()  
  20.         obj.add(self, conn)  
  21.         obj.add(other, conn)  
  22.         return obj  
  23.   
  24.     def __or__(self, other):  
  25.         return self._combine(other, self.OR)  
  26.   
  27.     def __and__(self, other):  
  28.         return self._combine(other, self.AND)  
  29.   
  30.     def __invert__(self):  
  31.         obj = type(self)()  
  32.         obj.add(selfself.AND)  
  33.         obj.negate()  
  34.         return obj  

 

傳Q對象,構造搜索條件

 

首先還是需要導入模塊:

from django.db.models import Q

傳入條件進行查詢:

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))
    
models.Tb1.objects.filter(q1)

合並條件進行查詢:

con = Q()

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))

q2 = Q()
q2.connector = 'OR'
q2.children.append(('status', '在線'))

con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM