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)
相关文章
相关标签/搜索