Django中Q查詢及Q()對象

問題

通常咱們在Django程序中查詢數據庫操做都是在QuerySet裏進行進行,例以下面代碼:html

>>> 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())   

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

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

隨着咱們的程序愈來愈複雜,查詢的條件也跟着複雜起來,這樣簡單的經過一個filter()來進行查詢的條件將致使咱們的查詢愈來愈長。sql

 

 

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

當咱們在查詢的條件中須要組合條件時(例如兩個條件「且」或者「或」)時。咱們可使用Q()查詢對象。例以下面的代碼數據庫

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

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

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

使用上述代碼可使用SQL語句這麼理解:swift

WHEREquestionLIKE 'Who%' ORquestionLIKE 'What%'
 

咱們能夠在Q()對象的前面使用字符「~」來表明意義「非」,例以下面代碼:app

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

對應SQL語句能夠理解爲:函數

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

這樣咱們可使用 「&」或者「|」還有括號來對條件進行分組從而組合成更加複雜的查詢邏輯。post

也能夠傳遞多個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對象

對象 (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(self, self.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)
相關文章
相關標籤/搜索