1. 程式人生 > >Django中Q查詢及Q()對象

Django中Q查詢及Q()對象

weight omd today elf 參數 import ldr 對象之間的關系 成了

問題

一般我們在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. class Q(tree.Node):
  3. """
  4. Encapsulates filters as objects that can then be combined logically (using
  5. & and |).
  6. """
  7. # Connection types
  8. AND = ‘AND‘
  9. OR = ‘OR‘
  10. default = AND
  11. def __init__(self, *args, **kwargs):
  12. super(Q, self).__init__(children=list(args) + kwargs.items())
  13. def _combine(self, other, conn):
  14. if not isinstance(other, Q):
  15. raise TypeError(other)
  16. obj = type(self)()
  17. obj.add(self, conn)
  18. obj.add(other, conn)
  19. return obj
  20. def __or__(self, other):
  21. return self._combine(other, self.OR)
  22. def __and__(self, other):
  23. return self._combine(other, self.AND)
  24. def __invert__(self):
  25. obj = type(self)()
  26. obj.add(self, self.AND)
  27. obj.negate()
  28. 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)

Django中Q查詢及Q()對象